#include "FuriousTourist.h"
#include <assert.h>
#include <fstream>
using std::ifstream;
#include <cstring>
#include <time.h>

const int MAX_CHARS_PER_LINE = 512;
const int MAX_TOKENS_PER_LINE = 20;
const char* const DELIMITER = " ";

////////////////////////////////////////////////
// Function Declarations
////////////////////////////////////////////////
bool ConvertToFloat( char *c , float &f );
bool ConvertToInt( char *c , int &f );

////////////////////////////////////////////////
// Constructor()
//
// Most basic initialization of the game object.
////////////////////////////////////////////////
FuriousTourist::FuriousTourist(HINSTANCE hInstance, std::string winCaption, D3DDEVTYPE devType, DWORD requestedVP)
: 
d3dapplication(hInstance, winCaption, devType, requestedVP),
physics::PhysicsEngine(PHYSICS_MAX_CONTACTS, PHYSICS_MAX_ITERATIONS)
{
	srand(time(NULL));

	// assume we initialize in windowed mode
	mWindowed = true;

	// make these NULL for safety's sake
	mpD3DSprite = NULL;
	mpD3DMenuFont = NULL;
	mpD3DSmallMenuFont = NULL;
	mpD3DSmallFont = NULL;
	mpD3DLargeFont = NULL;

	// get the device capabilities. If this fails, there's
	// no device we can work with.
	if(!checkDeviceCaps())
	{
		MessageBox(0, "checkDeviceCaps() Failed", 0, 0);
		PostQuitMessage(0);
	}

	// initialize vertex declarations which we will use
	// in the shader
	InitAllVertexDeclarations();

	// initialize the sound engine
	SOUNDMANAGER->Initialize();

	mShowHealth = false;
	mGameOver = false;

	// load basic game assets
	LoadAssets();
}

////////////////////////////////////////////////
// Destructor()
//
// Uninitializes remaining objects.
////////////////////////////////////////////////
FuriousTourist::~FuriousTourist()
{
	// delete the menu buttons
	DeleteButtons(mMainMenuButtons);
	DeleteButtons(mOptionsButtons);
	DeleteButtons(mLevelSelectButtons);
	DeleteButtons(mCreditsButtons);
	DeleteButtons(mHelpButtons);

	// release textures
	mMenuBackgroundTex->Release();
	mMenuTitleTex->Release();
	mWinLoseScreenTex->Release();
	mWinTouristTex->Release();
	mLoseTouristTex->Release();
	mStarTex->Release();

	// release sprite
	mpD3DSprite->Release();

	// release fonts
	mpD3DMenuFont->Release();
	mpD3DSmallMenuFont->Release();
	mpD3DSmallFont->Release();
	mpD3DLargeFont->Release();

	// release FX file
	mFX->Release();

	// release sounds
	SOUNDMANAGER->Release();

	MESHMANAGER->ClearAll();
	// destroy all vertex declarations
	DestroyAllVertexDeclarations();
}

////////////////////////////////////////////////
// checkDeviceCaps()
//
// check the device capabilities before we try to use the device
////////////////////////////////////////////////
bool FuriousTourist::checkDeviceCaps()
{
	D3DCAPS9 caps;
	HR(gD3DDevice->GetDeviceCaps(&caps));

	// Check for vertex shader version 2.0 support.
	if( caps.VertexShaderVersion < D3DVS_VERSION(2, 0) )
		return false;

	// Check for pixel shader version 2.0 support.
	if( caps.PixelShaderVersion < D3DPS_VERSION(2, 0) )
		return false;

	// Check render target support.  The adapter format can be either the display mode format
	// for windowed mode, or D3DFMT_X8R8G8B8 for fullscreen mode, so we need to test against
	// both.  We use D3DFMT_R32F as the render texture format and D3DFMT_D24X8 as the 
	// render texture depth format.
	D3DDISPLAYMODE mode;
	mD3DObject->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &mode);

	// Windowed.
	if(FAILED(mD3DObject->CheckDeviceFormat(D3DADAPTER_DEFAULT, mDevType, mode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, D3DFMT_R32F)))
		return false;
	if(FAILED(mD3DObject->CheckDepthStencilMatch(D3DADAPTER_DEFAULT, mDevType, mode.Format,	D3DFMT_R32F, D3DFMT_D24X8)))
		return false;

	// Fullscreen.
	if(FAILED(mD3DObject->CheckDeviceFormat(D3DADAPTER_DEFAULT, mDevType, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, D3DFMT_R32F)))
		return false;
	if(FAILED(mD3DObject->CheckDepthStencilMatch(D3DADAPTER_DEFAULT, mDevType, D3DFMT_X8R8G8B8,	D3DFMT_R32F, D3DFMT_D24X8)))
		return false;


	return true;
}

////////////////////////////////////////////////
// onLostDevice()
//
// Performs necessary D3DX function calls when the
// d3d device is lost
////////////////////////////////////////////////
void FuriousTourist::OnLostDevice()
{
	// run 'OnLostDevice()' for every relevant object when necessary

	HR(mpD3DSprite->OnLostDevice());
	HR(mpD3DSmallFont->OnLostDevice());
	HR(mpD3DMenuFont->OnLostDevice());
	HR(mpD3DSmallMenuFont->OnLostDevice());
	HR(mpD3DLargeFont->OnLostDevice());
	HR(mFX->OnLostDevice());
}

////////////////////////////////////////////////
// onResetDevice()
//
// Performs necessary D3DX function calls when teh
// d3d device is reset
////////////////////////////////////////////////
void FuriousTourist::OnResetDevice()
{
	// run 'OnResetDevice()' for every relevant object when necessary

	HR(mpD3DSprite->OnResetDevice());
	HR(mpD3DSmallFont->OnResetDevice());
	HR(mpD3DMenuFont->OnResetDevice());
	HR(mpD3DSmallMenuFont->OnResetDevice());
	HR(mpD3DLargeFont->OnResetDevice());
	HR(mFX->OnResetDevice());

	// reset the positions of the menu buttons
	Buttons::iterator i = mMainMenuButtons.begin();
	while (i != mMainMenuButtons.end())
	{
		(*i)->UpdateSize(BACKBUFFERSIZE);
		i++;
	}

	i = mLevelSelectButtons.begin();
	while (i != mLevelSelectButtons.end())
	{
		(*i)->UpdateSize(BACKBUFFERSIZE);
		i++;
	}

	i = mCreditsButtons.begin();
	while (i != mCreditsButtons.end())
	{
		(*i)->UpdateSize(BACKBUFFERSIZE);
		i++;
	}

	i = mHelpButtons.begin();
	while (i != mHelpButtons.end())
	{
		(*i)->UpdateSize(BACKBUFFERSIZE);
		i++;
	}

	i = mOptionsButtons.begin();
	while (i != mOptionsButtons.end())
	{
		(*i)->UpdateSize(BACKBUFFERSIZE);
		i++;
	}

	i = mInGameHelpButtons.begin();
	while (i != mInGameHelpButtons.end())
	{
		(*i)->UpdateSize(BACKBUFFERSIZE);
		i++;
	}

	i = mWinLoseScreenButtons.begin();
	while (i != mWinLoseScreenButtons.end())
	{
		(*i)->UpdateSize(BACKBUFFERSIZE);
		i++;
	}
}

////////////////////////////////////////////////
// Update()
//
// The Main update command. Calls other Updates
// based on the current state. Also handles mouse
// input to ensure the button isn't clicked every
// frame.
////////////////////////////////////////////////
void FuriousTourist::Update(float dt)
{
	// get the latest keyboard/mouse states
	gameInput->poll();

	if (!gameInput->mouseButtonDown(0))
	{
		if (!mButtonReady)
			mButtonReleased = true;

		mButtonReady = true;
	}


	if(gameInput->mouseButtonDown(0) && mButtonReady)
	{
		mButtonDown = true;
		mButtonReady = false;
	}

	// update based on the game state
	switch(mState)
	{
	case GAMESTATE_INTRO:
		//PlayIntroMovie();
		SOUNDMANAGER->MusicPlay(MUSIC_TITLE);
		mState = GAMESTATE_MENU;
		break;
	case GAMESTATE_MENU:
		UpdateMenu(dt);
		break;
	case GAMESTATE_CREDITS:
		UpdateCredits(dt);
		break;
	case GAMESTATE_OPTIONS:
		UpdateOptions(dt);
		break;
	case GAMESTATE_PLAY:
		UpdateGame(dt);
		break;
	case GAMESTATE_LEVELSELECT:
		UpdateLevelSelect(dt);
		break;
	case GAMESTATE_HELP:
		UpdateHelp(dt);
		break;
	case GAMESTATE_QUIT:
		PostMessage(mhMainWnd, WM_QUIT, 0, 0); // send a message to this program, telling it to close
		break;
	default:
		break;
	}

	if(mButtonDown)
	{
		mButtonDown = false;
		mButtonReady = false;
		mButtonReleased = false;
	}

	UpdateFPS(dt);
}

////////////////////////////////////////////////
// UpdateMenu()
//
// Updates the main menu by handling button hi-lighting
// and mouse input
////////////////////////////////////////////////
void FuriousTourist::UpdateMenu(float dt)
{
	MoveTitleGraphic(dt);

	Buttons::iterator i = mMainMenuButtons.begin();
	while (i != mMainMenuButtons.end())
	{
		if ((*i)->isMouseOver())
			(*i)->Pressed();
		else
			(*i)->Unpressed();
		i++;
	}

	i = mMainMenuButtons.begin();
	while (i != mMainMenuButtons.end())
	{
		// get mouse input, location and check against appropriate button
		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_PLAY)
		{
			SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
			mCurrentLevel = 1;
			mState = GAMESTATE_LEVELSELECT;
			CreateLevelSelectButtons();
			//InitGame();
			return;
		}

		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_QUIT)
		{
			SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
			mState = GAMESTATE_QUIT;
			return;
		}

		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_CREDITS)
		{
			SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
			mState = GAMESTATE_CREDITS;
			return;
		}

		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_OPTIONS)
		{
			SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
			mState = GAMESTATE_OPTIONS;
			return;
		}

		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_HELP)
		{
			SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
			mState = GAMESTATE_HELP;
			return;
		}

		i++;
	}

}

////////////////////////////////////////////////
// UpdateLevelSelect()
//
// Updates the level seelction menu
////////////////////////////////////////////////
void FuriousTourist::UpdateLevelSelect(float dt)
{
	MoveTitleGraphic(dt);

	Buttons::iterator i = mLevelSelectButtons.begin();
	while (i != mLevelSelectButtons.end())
	{
		if ((*i)->isMouseOver())
			(*i)->Pressed();
		else
			(*i)->Unpressed();
		i++;
	}

	i = mLevelSelectButtons.begin();
	while (i != mLevelSelectButtons.end())
	{
		// get mouse input, location and check against appropriate button
		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_BACK)
		{
			mState = GAMESTATE_MENU;
			return;
		}

		UINT id = (*i)->GetID();

		if (mButtonDown && (*i)->isMouseOver() && id > BUTTON_LEVELSTART && id < BUTTON_LEVELEND)
		{
			if (id - BUTTON_LEVELSTART > mUnlockedLevel)
			{
				SOUNDMANAGER->SoundPlay(SOUND_MENUERROR);
				return;
			}
			else
			{
				SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
				mCurrentLevel = id - BUTTON_LEVELSTART;
				// these buttons need to be dynamically each time we start
				// so delete them here
				DeleteButtons(mLevelSelectButtons); 
				InitGame();
				SOUNDMANAGER->MusicStop();
				mState = GAMESTATE_PLAY;
				return;
			}
		}
		i++;
	}
}

////////////////////////////////////////////////
// UpdateHelp()
//
// Updates the help menu by handling button hi-lighting
// and mouse input
////////////////////////////////////////////////
void FuriousTourist::UpdateHelp(float dt)
{
	MoveTitleGraphic(dt);

	Buttons::iterator i = mHelpButtons.begin();
	while (i != mHelpButtons.end())
	{
		if ((*i)->isMouseOver())
			(*i)->Pressed();
		else
			(*i)->Unpressed();
		i++;
	}

	i = mHelpButtons.begin();
	while (i != mHelpButtons.end())
	{
		// get mouse input, location and check against appropriate button
		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_BACK)
		{
			SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
			mState = GAMESTATE_MENU;
			return;
		}
		i++;
	}
}

////////////////////////////////////////////////
// UpdateCredits()
//
// Updates the credits menu by handling button hi-lighting
// and mouse input
////////////////////////////////////////////////
void FuriousTourist::UpdateCredits(float dt)
{
	MoveTitleGraphic(dt);

	Buttons::iterator i = mCreditsButtons.begin();
	while (i != mCreditsButtons.end())
	{
		if ((*i)->isMouseOver())
			(*i)->Pressed();
		else
			(*i)->Unpressed();
		i++;
	}

	i = mCreditsButtons.begin();
	while (i != mCreditsButtons.end())
	{
		// get mouse input, location and check against appropriate button
		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_BACK)
		{
			SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
			mGameOver = false;
			mState = GAMESTATE_MENU;
			return;
		}
		i++;
	}
}

////////////////////////////////////////////////
// UpdateOptions()
//
// Updates the options menu by handling button hi-lighting
// and mouse input
////////////////////////////////////////////////
void FuriousTourist::UpdateOptions(float dt)
{
	MoveTitleGraphic(dt);

	Buttons::iterator i = mOptionsButtons.begin();
	while (i != mOptionsButtons.end())
	{
		if ((*i)->isMouseOver())
			(*i)->Pressed();
		else
			(*i)->Unpressed();
		i++;
	}

	i = mOptionsButtons.begin();
	while (i != mOptionsButtons.end())
	{
		bool updateVolume = false;

		if (mWindowed)
		{
			if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_FULLSCREEN)
			{
				SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
				EnableFullScreenMode(true);
				mWindowed = !mWindowed;
				return;
			}
		}
		else
		{
			if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_WINDOWED)
			{
				SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
				EnableFullScreenMode(false);
				mWindowed = !mWindowed;
				return;
			}
		}

		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_BACK)
		{
			SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
			mState = GAMESTATE_MENU;
			return;
		}

		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_SOUNDUP)
		{
			// sound is handled by volume function
			IncreaseVolume(mSoundVolume);
			return;
		}

		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_SOUNDDOWN)
		{
			DecreaseVolume(mSoundVolume);
			updateVolume = true;
		}

		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_MUSICUP)
		{
			IncreaseVolume(mMusicVolume);
			updateVolume = true;
		}

		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_MUSICDOWN)
		{
			DecreaseVolume(mMusicVolume);
			updateVolume = true;
		}

		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_CONTROLS)
		{
			SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
			mLaunchOnRelease = !mLaunchOnRelease;
			updateVolume = true;
		}

		if (updateVolume)
			SOUNDMANAGER->SetVolume(mSoundVolume, mMusicVolume);

		i++;
	}
}

////////////////////////////////////////////////
// UpdateFPS()
//
// Updates the current FPS counter in the game
////////////////////////////////////////////////
void FuriousTourist::UpdateFPS(float dt)
{
	// static variables so the values persist
	static float numFrames		= 0;
	static float timeElapsed	= 0.0f;

	// increment frames
	numFrames += 1.0f;

	// accumulate time
	timeElapsed += dt;

	// check if one second has passed. If so compute the FPS and print
	if (timeElapsed >= 1.0f)
	{
		mFPS = numFrames;

		timeElapsed = 0.0f;
		numFrames = 0.0f;
	}
}

////////////////////////////////////////////////
// CheckAmbientSound()
//
// Checks if an ambient sound needs to play this iteration
////////////////////////////////////////////////
void FuriousTourist::CheckAmbientSound(float dt)
{
	mAmbientTriggerTime += dt;

	if (mAmbientTriggerTime > AMBIENTRANDOM_MINDELAY)
	{
		float r = GetRandomFloat(0.0f, 1.0f);
		if (r < AMBIENTRANDOM_PROCCHANCE)
		{
			SOUNDMANAGER->SoundPlay(SOUND_AMBIENTRANDOM1 + (rand() % AMBIENTRANDOM_NUM));
			mAmbientTriggerTime = 0.0f;
		}
	}
}

////////////////////////////////////////////////
// UpdateGame()
//
// The Update loop of the game itself (GAMESTATE_PLAY)
// Handles player input, checks for win/loss conditions
// and initiates new Rounds. Is also interrupted if
// help screens need to be displayed
////////////////////////////////////////////////
void FuriousTourist::UpdateGame(float dt)
{
	SOUNDMANAGER->Update();
	TEXTMANAGER->Update(dt);

	// update the help screen buttons
	if (mDisplayInGameHelp)
	{
		Buttons::iterator b = mInGameHelpButtons.begin();
		while (b != mInGameHelpButtons.end())
		{
			if ((*b)->isMouseOver())
				(*b)->Pressed();
			else
				(*b)->Unpressed();
			b++;
		}

		b = mInGameHelpButtons.begin();
		while (b != mInGameHelpButtons.end())
		{
			if (mButtonDown)
			{
				if ((*b)->isMouseOver())
				{
					int id = (*b)->GetID();
					int size = mHelpScreens.size();

					switch(id)
					{
					case BUTTON_PREVHELP:
						if (mCurrentHelpScreen != 0)
							mCurrentHelpScreen--;
						break;

					case BUTTON_NEXTHELP:
						if (mCurrentHelpScreen < size)
							mCurrentHelpScreen++;
						break;

					case BUTTON_DONEHELP:
						if (mCurrentHelpScreen == size)
						{
							mDisplayInGameHelp = false;
							SOUNDMANAGER->SoundPlay(SOUND_BEACHAMBIENCE);
						}
						break;
					
					}
				}
			}
			b++;
		}
				
		// don't do any updating beyond this point, if we have help screens to show
		return;
	}

	if (mBeginWinScreenDelay)
		mTimeElapsedSinceWin += dt;

	if (mTimeElapsedSinceWin > ENDGAME_WAITOSHOWENDSCREEN)
		mDisplayWinScreen = true;

	int highScore = 0;

	// update the end game score buttons (use the InGameHelp buttons
	// for simplicity
	if (mDisplayWinScreen || mDisplayLoseScreen)
	{
		mTimeElapsedSinceShowScore += dt;

		Buttons::iterator b = mWinLoseScreenButtons.begin();
		while (b != mWinLoseScreenButtons.end())
		{
			int id = (*b)->GetID();

			if (mDisplayLoseScreen && id == BUTTON_NEXTLEVEL)
			{
				// don't update the 'next level' button
				// on the lose screen
			}
			else
			{
				if ((*b)->isMouseOver())
					(*b)->Pressed();
				else
					(*b)->Unpressed();
			}
			b++;
		}

		b = mWinLoseScreenButtons.begin();
		while (b != mWinLoseScreenButtons.end())
		{
			if (mButtonDown)
			{
				if ((*b)->isMouseOver())
				{
					int id = (*b)->GetID();

					switch(id)
					{
					case BUTTON_NEXTLEVEL:

						if (mDisplayWinScreen)
						{
							highScore = GetHighScore();
							if (mScore > highScore)
								SaveHighScore();

							mCurrentLevel++;
							if (mCurrentLevel > NUM_LEVELS)
							{	
								// game over
								DestroyGameAssets();
								SOUNDMANAGER->SoundStop();
								SOUNDMANAGER->MusicPlay(MUSIC_TITLE);
								mState = GAMESTATE_CREDITS;
								mGameOver = true;
								return;
							} 
							else
							{
								// load the next level
								ReplaceUnlockedLevel(mCurrentLevel);
								InitGame();
								return;
							}
						}
						break;

					case BUTTON_RETRYLEVEL:

						if (mDisplayWinScreen)
						{
							ReplaceUnlockedLevel(mCurrentLevel+1);

							highScore = GetHighScore();
							if (mScore > highScore)
								SaveHighScore();
						}
						InitGame();
						return;

					case BUTTON_BACKTOMENU:
						// game over
						if (mDisplayWinScreen)
						{
							ReplaceUnlockedLevel(mCurrentLevel+1);
							highScore = GetHighScore();
							if (mScore > highScore)
								SaveHighScore();
						}

						DestroyGameAssets();
						SOUNDMANAGER->SoundStop();
						SOUNDMANAGER->MusicPlay(MUSIC_TITLE);
						mState = GAMESTATE_MENU;
						return;
						break;
					
					}
				}
			}
			b++;
		}
				
		// don't do any updating beyond this point, since we're only
		// rendering the end game score
		return;
	}

	// check if we need to play ambient sounds
	CheckAmbientSound(dt);

	// update button states
	Buttons::iterator i = mGameButtons.begin();
	while (i != mGameButtons.end())
	{
		if ((*i)->isMouseOver())
			(*i)->Pressed();
		else
			(*i)->Unpressed();
		i++;
	}

	i = mGameButtons.begin();
	while (i != mGameButtons.end())
	{
		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_RESET)
		{
			SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
			InitGame();
			return;
		}

		// if the user presses Esc
		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_MENU)
		{
			SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
			DestroyGameAssets();
			SOUNDMANAGER->SoundStop();
			SOUNDMANAGER->MusicPlay(MUSIC_TITLE);
			mState = GAMESTATE_MENU;
			return;
		}

		if (mButtonDown && (*i)->isMouseOver() && (*i)->GetID() == BUTTON_TOGGLEHEALTH)
		{
			GameObjects::iterator g = mGameObjects.begin();
			while (g != mGameObjects.end())
			{
				(*g)->ToggleShowHealth();
				mShowHealth = !mShowHealth;
				g++;
			}
			return;
		}

		i++;
	}

	

	// vectors we use to compute the force vector of
	// the launch based on the start position and the
	// cursor position
	physics::Vector3 cursorPos, vec, startPos;
	startPos = mProjectileStartPosition;

	D3DXMATRIX viewProj = mView * mProj;

	Particles::iterator p = mParticles.begin();
	while (p != mParticles.end())
	{
		if ((*p)->HasStopped())
		{
			PhysicsEngine::RemoveParticleEffect(*p);
			p = mParticles.erase(p);
		}
		else
		{
			
			(*p)->UpdateViewProjMatrix(viewProj);
			p++;
		}
	}

	// respond to the mouse button events
	// if we're in 'launch on release' mode
	// we should initiate it here
	if (mLaunchOnRelease)
	{
		if (mButtonReleased)
		{
			if (mProjectileState == PROJECTILESTATE_PREPARED)
			{
				LaunchProjectile(dt);
				mSpareWeapons--;
				mProjectileState = PROJECTILESTATE_INFLIGHT;
			}
		}
	}

	// don't accept user input while waiting for the level to end
	if(mButtonDown && !mBeginWinScreenDelay)
	{
		switch(mProjectileState)
		{
			// if we're ready to fire and clicked, then change the state to 'prepared' which will attach
			// the controllable sphere to the location cursor
		case PROJECTILESTATE_READY:
			if (mCameraMoving)
				break;
			SOUNDMANAGER->SoundPlay(SOUND_PROJECTILEPREPARE);
			mProjectileState = PROJECTILESTATE_PREPARED;
			break;

			// if we're prepared and clicked, then launch the projectile and set the state to 'in flight'
			// unless the projectile has no special ability, in which case skip to 'waiting'
		case PROJECTILESTATE_PREPARED:
			// if we're in 'launch on release' mode, we must
			// skip this code, since we handle that event above
			if (!mLaunchOnRelease)
			{
				LaunchProjectile(dt);
				mSpareWeapons--;
				mProjectileState = PROJECTILESTATE_INFLIGHT;
			}
			break;

			// if we're inflight and clicked, then activate the projectile's special ability
		case PROJECTILESTATE_INFLIGHT:	
			// activate special here
			if (!mSpecialUsed)
			{
				// clear markers from the previous shot
				if (mProjectile->GetType() == WEAPONTYPE_EXPLODE)
					ClearPreviousMarkers();
				mProjectile->SpecialAbility(this);
				mSpecialUsed = true;
			}
			
			break;

			// if we're 'waiting' and click, do nothing
		case PROJECTILESTATE_WAITING:
			if (mProjectile != NULL)
			{
				if (mProjectile->GetType() == WEAPONTYPE_EXPLODE)
				{
					if (!mSpecialUsed)
					{
						
						mProjectile->SpecialAbility(this);
						mSpecialUsed = true;
					}
				}
			}


			break;
		}
	}

	// If the user presses 'R'
	if (gameInput->keyDown(DIK_R))
	{
		InitGame(); // reset the current map
	}

	// if the user presses Esc
	if (gameInput->keyDown(DIK_ESCAPE))
	{
		DestroyGameAssets();
		SOUNDMANAGER->SoundStop();
		SOUNDMANAGER->MusicPlay(MUSIC_TITLE);
		mState = GAMESTATE_MENU;
		return;
	}
	
	GameObjects::iterator x = mGameObjects.begin();
	while (x != mGameObjects.end())
	{
		if ((*x)->GetMaterial() == OBJECTMATERIAL_BIRD)
		{
			physics::Vector3 vel = (*x)->GetBody()->getVelocity();
			if (vel.squareMagnitude() > BIRDSQUAWK_SPEED)
			{
				if (mPlaySquawk)
				{
					SOUNDMANAGER->SoundPlay(SOUND_BIRDSQUAWK);
					mPlaySquawk = false;
					break;
				}
			}
		}
		x++;
	}

	// update the game based on the state of the current projectile
	switch(mProjectileState)
	{
	case PROJECTILESTATE_READY:
		// this fixes an issue where if the round ends with an object resting on the projectile
		// it would cause an extra force the next time it was fired by clearing all values and
		// stopping its motion
		mProjectile->GetBody()->stop();
		break;
	
	case PROJECTILESTATE_PREPARED:
		// attach the sphere to the current position of the mouse cursor (need to do picking?)
		cursorPos = physics::Vector3(GetWorldPickingRay());
		vec = startPos - cursorPos;
		if (vec.squareMagnitude() > PROJECTILEPREPARED_DISTANCE * PROJECTILEPREPARED_DISTANCE)
		{
			vec.normalize();
			vec *= PROJECTILEPREPARED_DISTANCE;
		}
		mProjectile->GetBody()->setPosition(startPos - vec);
		break;

	case PROJECTILESTATE_INFLIGHT:
		// create a marker at regular intervals
		mTimeElapsedSinceCreatedLastMarker += dt;
		if (mTimeElapsedSinceCreatedLastMarker >= CREATEMARKER_TIME)
		{
			mTimeElapsedSinceCreatedLastMarker = 0.0f;
			CreateMarker();
		}

		// if the projectile collided with something, we need to start a counter, and go into the waiting state
		if (mProjectile == NULL)
		{
			mWaitCount = true;
			mProjectileState = PROJECTILESTATE_WAITING;
			mTimeElapsedSinceCollision = 0;
		}
		else if	(PhysicsEngine::HasCollided(mProjectile->GetBody()))
		{
			// clear markers from teh previous shot
			ClearPreviousMarkers();

			// wake everything up
			std::vector<physics::CollisionPrimitive*>::iterator i = PhysicsEngine::getObjects().begin();
			while (i != PhysicsEngine::getObjects().end())
			{
				if ((*i)->body != NULL)
					if ((*i)->body != mProjectile->GetBody())
						(*i)->body->setAwake();	
				i++;
			}

			if (mProjectile != NULL)
			{
				if (mProjectile->GetType() == WEAPONTYPE_EXPLODE)
				{
					mProjectile->SpecialAbility2();
				}
			}
			mProjectileState = PROJECTILESTATE_WAITING;
			mTimeElapsedSinceCollision = 0;
			mWaitCount = true;
		}
		break;

	case PROJECTILESTATE_WAITING:
		// we assume the counter has already been started during the transition from 'INFLIGHT'
		// start counting time
		if (mWaitCount)
		{
			float timeScale = 1.0f;
			// if the projectile is resting, increase the speed at which we move
			// to the next round
			if (mProjectile != NULL)
				if (!mProjectile->GetBody()->getAwake())
					timeScale *= PROJECTILE_SLEEPTIMEFACTOR;

			mTimeElapsedSinceCollision += timeScale * dt;
		}

		// if the projectile is not null (i.e. a bomb that previously exploded)
		if (mProjectile != NULL)
		{
			// if the projectile is a bomb
			if (mProjectile->GetType() == WEAPONTYPE_EXPLODE)
			{
				// if the special hasn't been used
				if (!mSpecialUsed)
				{
					// and a few seconds have passed
					if (mTimeElapsedSinceCollision > EXPLOSION_WAITTIME)
					{
						// blow up the bomb
						mProjectile->SpecialAbility(this);
						mSpecialUsed = true;
					}
				}
			}
		}

		if (mTimeElapsedSinceCollision > PROJECTILE_WAITTIME)
		{
			mWaitCount = false; // stop counting
			if (!mEndGameCount) // if the endgame counter hasn't started, load the next weapon. Otherwise wait until that counter ends
			{
				// reset the projectile's position and state
				if (!LoadNextWeapon())
				{
					// failing to load a weapon means we've run out of shots. The player has lost.
					mDisplayLoseScreen = true;
					return;
				}
				else
				{
					// successfully loading the weapon means we need to prepare the next round
					mSpecialUsed = false;
					mProjectile->GetBody()->setPosition(mProjectileStartPosition);
					mProjectile->GetBody()->stop();
					mProjectile->GetBody()->setOrientation(1, 0, 0, 0);
					mProjectileState = PROJECTILESTATE_READY;
					SOUNDMANAGER->SoundPlay(SOUND_PROJECTILELOAD);
					// only let the squawk sound play once per round
					mPlaySquawk = true;

					// just in case something was resting on top of the projectile when it
					// moved back, tell every object in the game to wake up
					std::vector<physics::CollisionPrimitive*>::iterator i = PhysicsEngine::getObjects().begin();
					while (i != PhysicsEngine::getObjects().end())
					{
						if ((*i)->body != NULL)
							if ((*i)->body != mProjectile->GetBody())
								(*i)->body->setAwake();	
						i++;
					}
					return;
				}
			}
		}
		break;
	}

	// if we've run out of birds, start counting towards the end of the game
	if (!mNumBirdsLeft && !mEndGameCount)
	{
		mEndGameCount = true;
		mEndGameTimer = 0.0f;
	}

	if (mEndGameCount && !mBeginWinScreenDelay)
	{
		mEndGameTimer += dt;
		if (mEndGameTimer > ENDGAME_WAITTIME)
			// the counter has reached its limit, end the game
		{
			// display the score. Will be shown in the next iteration
			SOUNDMANAGER->SoundPlay(SOUND_WIN);
			mScore += mSpareWeapons * SCORE_PERWEAPON;
			mBeginWinScreenDelay = true;
			// use iterator created earlier
			x = mWeapons.begin();
			int extraY = 0.0f;
			while (x != mWeapons.end())
			{
				if (((*x) == mProjectile) && (mProjectileState != PROJECTILESTATE_READY || mProjectileState != PROJECTILESTATE_PREPARED))
				{
					x++;
					continue;
				}
				D3DXVECTOR3 pos;
				if ((*x) == NULL)
				{
					x++;
					continue;
				}
				physics::Vector3 p = (*x)->GetBody()->getPosition();
				pos.x = p.x;
				pos.y = p.y + extraY;
				pos.z = p.z;
				D3DCOLOR color;
				switch((*x)->GetType())
				{
				case WEAPONTYPE_NORMAL:
					color = D3DCOLOR_XRGB(96, 57, 19);
					break;

				case WEAPONTYPE_MULTI:
					color = D3DCOLOR_XRGB(0, 84, 166);
					break;

				case WEAPONTYPE_ROCKET:
					color = D3DCOLOR_XRGB(237, 28, 36);
					break;

				case WEAPONTYPE_EXPLODE:
					color = D3DCOLOR_XRGB(0, 0, 0);
					break;
				}
				extraY += 3.5f;
				TEXTMANAGER->AddFloatingText(mpD3DMenuFont, SCORE_PERWEAPON, 1.5, GetScreenPosition(pos), 1.0, 1.5, color);
				x++;
			}
			return;
		}
	}

	// update all RigidBody objects with their new Physical properties (acc, vel, pos etc.)
	PhysicsEngine::update(dt);

	// remove the explosion force if needed
	if (mStopExplosion)
	{
		PhysicsEngine::globalRegistry.remove(mExplosiveForce);
		delete mExplosiveForce;
		mStopExplosion = false;
	}

	// check the health manager and apply damage
	// reuse the earlier iterator
	x = mGameObjects.begin();
	while (x != mGameObjects.end())
	{
		if ((*x)->HasHealth())
		{
			int health = (*x)->GetHP();
			int damage = HEALTHMANAGER->GetDamage((*x)->GetBody()) * (1 / GetDensity((*x)->GetMaterial()));
			if (damage > 0)
			{
				if (damage >= DAMAGE_MAXIMUM)
						damage = DAMAGE_MAXIMUM;

				(*x)->SetHP(health - damage);
				D3DXVECTOR3 pos;
				physics::Vector3 p = (*x)->GetBody()->getPosition();
				pos.x = p.x;
				pos.y = p.y;
				pos.z = p.z;
				
				if ((*x)->GetMaterial() != OBJECTMATERIAL_BIRD)
				{
					TEXTMANAGER->AddFloatingText(mpD3DSmallMenuFont, damage, SCORETEXT_LIFETIME, GetScreenPosition(pos), SCORETEXT_MINSCALE, SCORETEXT_MAXSCALE, SCORETEXT_COLOR);
					mScore += damage;
				}
			}
			
		}
		x++;
	}

	// destroy any game object that has zero or less health
	x = mGameObjects.begin();
	while (x != mGameObjects.end())
	{
		if ((*x)->GetHP() <= 0)
		{
			ParticleEffect *particles = new ParticleEffect(mpD3DSprite);
			SpriteData sData;
			
			physics::Vector3 pos;
			(*x)->GetBody()->getPosition(&pos);
			D3DXVECTOR3 p;
			p.x = pos.x;
			p.y = pos.y;
			p.z = 0.0f;
			float scale = sqrt((*x)->GetBody()->getMass());
			UINT obj = (*x)->GetType();
			UINT mat = (*x)->GetMaterial();
			switch(obj)
			{
			case BIRDTYPE_BLACKBIRD:
				sData.frameHeight = BIRDPARTICLE_H;
				sData.frameWidth = BIRDPARTICLE_W;
				sData.numCols = BIRDPARTICLE_NC;
				sData.numRows = BIRDPARTICLE_NR;
				scale *= BIRDDEATH_SCALEFACTOR;
				sData.filename = "Assets//Textures//Feather_Black.png";
				particles->AddParticles(20, sData, BIRDDEATH_MINSCALE * scale, BIRDDEATH_MAXSCALE * scale, BIRDDEATH_MINVEL, BIRDDEATH_MAXVEL, BIRDDEATH_MINANGVEL, BIRDDEATH_MAXANGVEL, BIRDDEATH_LIFETIME, pos, true);
				sData.filename = "Assets//Textures//Feather_Yellow.png";
				particles->AddParticles(10, sData, BIRDDEATH_MINSCALE * scale, BIRDDEATH_MAXSCALE * scale, BIRDDEATH_MINVEL, BIRDDEATH_MAXVEL, BIRDDEATH_MINANGVEL, BIRDDEATH_MAXANGVEL, BIRDDEATH_LIFETIME, pos, true);
				mParticles.push_back(particles);
				PhysicsEngine::AddParticleEffect(particles);
				SOUNDMANAGER->SoundPlay(SOUND_BLACKBIRDDEATH);
				TEXTMANAGER->AddFloatingText(mpD3DSmallMenuFont, SCORE_BIRDDEATH, SCORETEXT_LIFETIME, GetScreenPosition(p) + SCORETEXT_OBJECTDEATHPOS, SCORETEXT_MINSCALE, SCORETEXT_MAXSCALE, SCORETEXT_BLACKBIRDDEATHCOLOR);
				mScore += SCORE_BIRDDEATH;
				break;

			case BIRDTYPE_PARROT:
				sData.frameHeight = BIRDPARTICLE_H;
				sData.frameWidth = BIRDPARTICLE_W;
				sData.numCols = BIRDPARTICLE_NC;
				sData.numRows = BIRDPARTICLE_NR;
				scale *= BIRDDEATH_SCALEFACTOR;
				sData.filename = "Assets//Textures//Feather_Blue.png";
				particles->AddParticles(10, sData, BIRDDEATH_MINSCALE * scale, BIRDDEATH_MAXSCALE * scale, BIRDDEATH_MINVEL, BIRDDEATH_MAXVEL, BIRDDEATH_MINANGVEL, BIRDDEATH_MAXANGVEL, BIRDDEATH_LIFETIME, pos, true);
				sData.filename = "Assets//Textures//Feather_Red.png";
				particles->AddParticles(10, sData, BIRDDEATH_MINSCALE * scale, BIRDDEATH_MAXSCALE * scale, BIRDDEATH_MINVEL, BIRDDEATH_MAXVEL, BIRDDEATH_MINANGVEL, BIRDDEATH_MAXANGVEL, BIRDDEATH_LIFETIME, pos, true);
				sData.filename = "Assets//Textures//Feather_Green.png";
				particles->AddParticles(10, sData, BIRDDEATH_MINSCALE * scale, BIRDDEATH_MAXSCALE * scale, BIRDDEATH_MINVEL, BIRDDEATH_MAXVEL, BIRDDEATH_MINANGVEL, BIRDDEATH_MAXANGVEL, BIRDDEATH_LIFETIME, pos, true);
				mParticles.push_back(particles);
				PhysicsEngine::AddParticleEffect(particles);
				SOUNDMANAGER->SoundPlay(SOUND_PARROTDEATH);
				TEXTMANAGER->AddFloatingText(mpD3DSmallMenuFont, SCORE_BIRDDEATH, SCORETEXT_LIFETIME, GetScreenPosition(p) + SCORETEXT_OBJECTDEATHPOS, SCORETEXT_MINSCALE, SCORETEXT_MAXSCALE, SCORETEXT_PARROTDEATHCOLOR);
				mScore += SCORE_BIRDDEATH;
				break;

			case BIRDTYPE_SEAGULL:
				sData.frameHeight = BIRDPARTICLE_H;
				sData.frameWidth = BIRDPARTICLE_W;
				sData.numCols = BIRDPARTICLE_NC;
				sData.numRows = BIRDPARTICLE_NR;
				scale *= BIRDDEATH_SCALEFACTOR;
				sData.filename = "Assets//Textures//Feather_White.png";
				particles->AddParticles(20, sData, BIRDDEATH_MINSCALE * scale, BIRDDEATH_MAXSCALE * scale, BIRDDEATH_MINVEL, BIRDDEATH_MAXVEL, BIRDDEATH_MINANGVEL, BIRDDEATH_MAXANGVEL, BIRDDEATH_LIFETIME, pos, true);
				sData.filename = "Assets//Textures//Feather_Grey.png";
				particles->AddParticles(10, sData, BIRDDEATH_MINSCALE * scale, BIRDDEATH_MAXSCALE * scale, BIRDDEATH_MINVEL, BIRDDEATH_MAXVEL, BIRDDEATH_MINANGVEL, BIRDDEATH_MAXANGVEL, BIRDDEATH_LIFETIME, pos, true);
				mParticles.push_back(particles);
				PhysicsEngine::AddParticleEffect(particles);
				SOUNDMANAGER->SoundPlay(SOUND_SEAGULLDEATH);
				TEXTMANAGER->AddFloatingText(mpD3DSmallMenuFont, SCORE_BIRDDEATH, SCORETEXT_LIFETIME, GetScreenPosition(p) + SCORETEXT_OBJECTDEATHPOS, SCORETEXT_MINSCALE, SCORETEXT_MAXSCALE, SCORETEXT_SEAGULLDEATHCOLOR);
				mScore += SCORE_BIRDDEATH;
				break;

			case BIRDTYPE_TOUCAN:
				sData.frameHeight = BIRDPARTICLE_H;
				sData.frameWidth = BIRDPARTICLE_W;
				sData.numCols = BIRDPARTICLE_NC;
				sData.numRows = BIRDPARTICLE_NR;
				scale *= BIRDDEATH_SCALEFACTOR;
				sData.filename = "Assets//Textures//Feather_Black.png";
				particles->AddParticles(15, sData, BIRDDEATH_MINSCALE * scale, BIRDDEATH_MAXSCALE * scale, BIRDDEATH_MINVEL, BIRDDEATH_MAXVEL, BIRDDEATH_MINANGVEL, BIRDDEATH_MAXANGVEL, BIRDDEATH_LIFETIME, pos, true);
				sData.filename = "Assets//Textures//Feather_Blue.png";
				particles->AddParticles(5, sData, BIRDDEATH_MINSCALE * scale, BIRDDEATH_MAXSCALE * scale, BIRDDEATH_MINVEL, BIRDDEATH_MAXVEL, BIRDDEATH_MINANGVEL, BIRDDEATH_MAXANGVEL, BIRDDEATH_LIFETIME, pos, true);
				sData.filename = "Assets//Textures//Feather_Green.png";
				particles->AddParticles(5, sData, BIRDDEATH_MINSCALE * scale, BIRDDEATH_MAXSCALE * scale, BIRDDEATH_MINVEL, BIRDDEATH_MAXVEL, BIRDDEATH_MINANGVEL, BIRDDEATH_MAXANGVEL, BIRDDEATH_LIFETIME, pos, true);
				sData.filename = "Assets//Textures//Feather_Orange.png";
				particles->AddParticles(5, sData, BIRDDEATH_MINSCALE * scale, BIRDDEATH_MAXSCALE * scale, BIRDDEATH_MINVEL, BIRDDEATH_MAXVEL, BIRDDEATH_MINANGVEL, BIRDDEATH_MAXANGVEL, BIRDDEATH_LIFETIME, pos, true);
				mParticles.push_back(particles);
				PhysicsEngine::AddParticleEffect(particles);
				SOUNDMANAGER->SoundPlay(SOUND_TOUCANDEATH);
				TEXTMANAGER->AddFloatingText(mpD3DSmallMenuFont, SCORE_BIRDDEATH, SCORETEXT_LIFETIME, GetScreenPosition(p) + SCORETEXT_OBJECTDEATHPOS, SCORETEXT_MINSCALE, SCORETEXT_MAXSCALE, SCORETEXT_TOUCANDEATHCOLOR);
				mScore += SCORE_BIRDDEATH;
				break;

			}

			switch(mat)
			{
			case OBJECTMATERIAL_WOOD:
				sData.frameHeight = WOODPARTICLE_H;
				sData.frameWidth = WOODPARTICLE_W;
				sData.numCols = WOODPARTICLE_NC;
				sData.numRows = WOODPARTICLE_NR;
				scale *= WOODDEATH_SCALEFACTOR;
				sData.filename = "Assets//Textures//WoodChip1.png";
				particles->AddParticles(5, sData, WOODDEATH_MINSCALE * scale, WOODDEATH_MAXSCALE * scale, WOODDEATH_MINVEL, WOODDEATH_MAXVEL, WOODDEATH_MINANGVEL, WOODDEATH_MAXANGVEL, WOODDEATH_LIFETIME, pos, true, physics::Vector3::DOWN * GRAVITY_STRENGTH);
				sData.filename = "Assets//Textures//WoodChip2.png";
				particles->AddParticles(5, sData, WOODDEATH_MINSCALE * scale, WOODDEATH_MAXSCALE * scale, WOODDEATH_MINVEL, WOODDEATH_MAXVEL, WOODDEATH_MINANGVEL, WOODDEATH_MAXANGVEL, WOODDEATH_LIFETIME, pos, true, physics::Vector3::DOWN * GRAVITY_STRENGTH);
				sData.filename = "Assets//Textures//WoodChip3.png";
				particles->AddParticles(5, sData, WOODDEATH_MINSCALE * scale, WOODDEATH_MAXSCALE * scale, WOODDEATH_MINVEL, WOODDEATH_MAXVEL, WOODDEATH_MINANGVEL, WOODDEATH_MAXANGVEL, WOODDEATH_LIFETIME, pos, true, physics::Vector3::DOWN * GRAVITY_STRENGTH);
				mParticles.push_back(particles);
				PhysicsEngine::AddParticleEffect(particles);
				SOUNDMANAGER->SoundPlay(SOUND_WOODBREAK);
				TEXTMANAGER->AddFloatingText(mpD3DSmallMenuFont, SCORE_OBJECTDEATH, SCORETEXT_LIFETIME, GetScreenPosition(p) + SCORETEXT_OBJECTDEATHPOS, SCORETEXT_MINSCALE, SCORETEXT_MAXSCALE, SCORETEXT_OBJECTDEATHCOLOR);
				mScore += SCORE_OBJECTDEATH;
				break;

			case OBJECTMATERIAL_STONE:
				sData.frameHeight = STONEPARTICLE_H;
				sData.frameWidth = STONEPARTICLE_W;
				sData.numCols = STONEPARTICLE_NC;
				sData.numRows = STONEPARTICLE_NR;
				scale *= STONEDEATH_SCALEFACTOR;
				sData.filename = "Assets//Textures//StoneChip1.png";
				particles->AddParticles(5, sData, STONEDEATH_MINSCALE * scale, STONEDEATH_MAXSCALE * scale, STONEDEATH_MINVEL, STONEDEATH_MAXVEL, STONEDEATH_MINANGVEL, STONEDEATH_MAXANGVEL, STONEDEATH_LIFETIME, pos, true, physics::Vector3::DOWN * GRAVITY_STRENGTH);
				sData.filename = "Assets//Textures//StoneChip2.png";
				particles->AddParticles(5, sData, STONEDEATH_MINSCALE * scale, STONEDEATH_MAXSCALE * scale, STONEDEATH_MINVEL, STONEDEATH_MAXVEL, STONEDEATH_MINANGVEL, STONEDEATH_MAXANGVEL, STONEDEATH_LIFETIME, pos, true, physics::Vector3::DOWN * GRAVITY_STRENGTH);
				sData.filename = "Assets//Textures//StoneChip3.png";
				particles->AddParticles(5, sData, STONEDEATH_MINSCALE * scale, STONEDEATH_MAXSCALE * scale, STONEDEATH_MINVEL, STONEDEATH_MAXVEL, STONEDEATH_MINANGVEL, STONEDEATH_MAXANGVEL, STONEDEATH_LIFETIME, pos, true, physics::Vector3::DOWN * GRAVITY_STRENGTH);
				mParticles.push_back(particles);
				PhysicsEngine::AddParticleEffect(particles);
				SOUNDMANAGER->SoundPlay(SOUND_STONEBREAK);
				TEXTMANAGER->AddFloatingText(mpD3DSmallMenuFont, SCORE_OBJECTDEATH, SCORETEXT_LIFETIME, GetScreenPosition(p) + SCORETEXT_OBJECTDEATHPOS, SCORETEXT_MINSCALE, SCORETEXT_MAXSCALE, SCORETEXT_OBJECTDEATHCOLOR);
				mScore += SCORE_OBJECTDEATH;
				break;

			case OBJECTMATERIAL_EXPLOSIVE:
				(*x)->GetBody()->getPosition(&pos);
				GenerateExplosion(pos);
				break;

			case OBJECTMATERIAL_BIRD:
				SOUNDMANAGER->SoundPlay(SOUND_POP);
				break;
			}


			// if the object is a bird, we need to decrement the count
			if ((*x)->GetMaterial() == OBJECTMATERIAL_BIRD)
				mNumBirdsLeft--;
			physics::RigidBody* body = (*x)->GetBody(); // keep a pointer to the body for a moment
			x = mGameObjects.erase(x); // remove the object from the game
			PhysicsEngine::RemoveObject(body); // remove the object from the physics engine			
		}
		else
		{
			x++;
		}
	}


	// clear erroneous events from the HealthManager
	HEALTHMANAGER->ClearAll();

	UpdateViewMatrix(dt);
}

////////////////////////////////////////////////
// Render()
//
// The main Render function. Calls the appropriate
// Render function depending on the current state.
////////////////////////////////////////////////
void FuriousTourist::Render()
{
	// render based on the game state
	switch(mState)
	{
	case GAMESTATE_INTRO:
		break;
	case GAMESTATE_MENU:
		RenderMenu();
		break;
	case GAMESTATE_CREDITS:
		RenderCredits();
		break;
	case GAMESTATE_OPTIONS:
		RenderOptions();
		break;
	case GAMESTATE_LEVELSELECT:
		RenderLevelSelect();
		break;
	case GAMESTATE_PLAY:
		RenderGame();
		break;
	case GAMESTATE_HELP:
		RenderHelp();
		break;
	case GAMESTATE_QUIT:
		break;
	default:
		break;
	}
}

////////////////////////////////////////////////
// RenderMenu()
//
// Renders the main menu to the screen. Resizes
// objects based on the current backbuffer size.
////////////////////////////////////////////////
void FuriousTourist::RenderMenu()
{
	// render the current state of the game to the screen
	// Clear the backbuffer and depth buffer.
	HR(gD3DDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0));
	HR(gD3DDevice->BeginScene());

	mpD3DSprite->Begin(D3DXSPRITE_ALPHABLEND);

	RenderTitleGraphics();

	// reset the scaling matrix to render the buttons
	D3DXMATRIX S;
	D3DXMatrixScaling(&S, 1.0f, 1.0f, 1.0f);
	mpD3DSprite->SetTransform(&S);

	Buttons::iterator i = mMainMenuButtons.begin();
	while (i != mMainMenuButtons.end())
	{
		(*i)->Render();
		i++;
	}

	mpD3DSprite->End();
	
	HR(gD3DDevice->EndScene());
	HR(gD3DDevice->Present( NULL, NULL, NULL, NULL ));
}

////////////////////////////////////////////////
// RenderLevelSelect()
//
// Renders the level selection menu to the screen
////////////////////////////////////////////////
void FuriousTourist::RenderLevelSelect()
{
	// render the current state of the game to the screen
	// Clear the backbuffer and depth buffer.
	HR(gD3DDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0));
	HR(gD3DDevice->BeginScene());

	mpD3DSprite->Begin(D3DXSPRITE_ALPHABLEND);

	RenderTitleGraphics();
	
	// reset the scaling matrix to render the buttons
	D3DXMATRIX S;
	D3DXMatrixScaling(&S, 1.0f, 1.0f, 1.0f);
	mpD3DSprite->SetTransform(&S);

	Buttons::iterator i = mLevelSelectButtons.begin();
	while (i != mLevelSelectButtons.end())
	{
		(*i)->Render();
		i++;
	}

	mpD3DSprite->End();
	
	HR(gD3DDevice->EndScene());
	HR(gD3DDevice->Present( NULL, NULL, NULL, NULL ));
}

////////////////////////////////////////////////
// RenderHelp()
//
// Renders the help menu to the screen. Resizes
// objects based on the current backbuffer size.
////////////////////////////////////////////////
void FuriousTourist::RenderHelp()
{
	// render the current state of the game to the screen
	// Clear the backbuffer and depth buffer.
	HR(gD3DDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0));
	HR(gD3DDevice->BeginScene());

	mpD3DSprite->Begin(D3DXSPRITE_ALPHABLEND);

	RenderTitleGraphics();

	D3DXMATRIX S;
	D3DXMatrixScaling(&S, 1.0f, 1.0f, 1.0f);
	mpD3DSprite->SetTransform(&S);
	
	Buttons::iterator i = mHelpButtons.begin();
	while (i != mHelpButtons.end())
	{
		(*i)->Render();
		i++;
	}

	mpD3DSprite->End();

	static char buffer[512];

	
	sprintf_s(buffer, "Get rid of those accursed birds!\n\n1) Hold the left mouse button to load your weapon\n2) Use the cursor to aim your weapon\n3) Release the mouse button to fire\n4) If the weapon has a special ability, click again to activate it\n5) Wait for the next weapon to be loaded\n\nPress R to reset the current level at any time\nPress Esc to return to the Main Menu at any time\nUse the RMB and Mouse Wheel to move the camera\nPress A/D to rotate the camera after the projectile has been launched.");

	RECT R1 = {mD3DPP.BackBufferWidth*0.4, mD3DPP.BackBufferHeight*0.6, 0, 0};
	if (mWindowed)
		mpD3DSmallFont->DrawTextA(0, buffer, -1, &R1, DT_NOCLIP, D3DCOLOR_ARGB(255, 0, 0, 0));
	else
		mpD3DLargeFont->DrawTextA(0, buffer, -1, &R1, DT_NOCLIP, D3DCOLOR_ARGB(255, 0, 0, 0));
	
	HR(gD3DDevice->EndScene());
	HR(gD3DDevice->Present( NULL, NULL, NULL, NULL ));
}

////////////////////////////////////////////////
// RenderCredits()
//
// Renders the credits menu to the screen. Resizes
// objects based on the current backbuffer size.
////////////////////////////////////////////////
void FuriousTourist::RenderCredits()
{
	// render the current state of the game to the screen
	// Clear the backbuffer and depth buffer.
	HR(gD3DDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0));
	HR(gD3DDevice->BeginScene());

	mpD3DSprite->Begin(D3DXSPRITE_ALPHABLEND);

	RenderTitleGraphics();

	D3DXMATRIX S;
	D3DXMatrixScaling(&S, 1.0f, 1.0f, 1.0f);
	mpD3DSprite->SetTransform(&S);
	
	Buttons::iterator i = mCreditsButtons.begin();
	while (i != mCreditsButtons.end())
	{
		(*i)->Render();
		i++;
	}

	mpD3DSprite->End();

	static char buffer[512];

	int w = mD3DPP.BackBufferWidth;
	int h = mD3DPP.BackBufferHeight;

	if (mGameOver)
	{
		sprintf_s(buffer, "Game Over!\nThanks for playing!");
		RECT R = {w*0.5, h*0.3, w*0.5, h*0.3};
		mpD3DMenuFont->DrawTextA(0, buffer, -1, &R, DT_NOCLIP | DT_CENTER, D3DCOLOR_ARGB(255, 255, 147, 0));
	}
	
	sprintf_s(buffer, "By Chris Dickinson\nGSP361 Course Project\nDeVry University\nApril 2012\n\nSome artwork provided by Google Images and their respective authors.\nCredit to Frank Luna (DirectX API) and Ian Millington\n(Physics Engine) for various pieces of code and artwork\nSpecial thanks to my wife, Jamie, for most of the modeling and texturing.\nSound effects obtained from www.sounddogs.com and www.grsites.com");

	RECT R1 = {w*0.35, h*0.55, w*0.35, h*0.55};
	if (mWindowed)
		mpD3DSmallFont->DrawTextA(0, buffer, -1, &R1, DT_NOCLIP, D3DCOLOR_ARGB(255, 0, 0, 0));
	else
		mpD3DLargeFont->DrawTextA(0, buffer, -1, &R1, DT_NOCLIP, D3DCOLOR_ARGB(255, 0, 0, 0));

	HR(gD3DDevice->EndScene());
	HR(gD3DDevice->Present( NULL, NULL, NULL, NULL ));
}

////////////////////////////////////////////////
// RenderOptions()
//
// Renders the options menu to the screen. Resizes
// objects based on the current backbuffer size.
////////////////////////////////////////////////
void FuriousTourist::RenderOptions()
{
	// render the current state of the game to the screen
	// Clear the backbuffer and depth buffer.
	HR(gD3DDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0));
	HR(gD3DDevice->BeginScene());

	mpD3DSprite->Begin(D3DXSPRITE_ALPHABLEND);

	RenderTitleGraphics();

	D3DXMATRIX S;
	D3DXMatrixScaling(&S, 1.0f, 1.0f, 1.0f);
	mpD3DSprite->SetTransform(&S);
	
	Buttons::iterator i = mOptionsButtons.begin();
	while (i != mOptionsButtons.end())
	{
		if (mWindowed)
		{
			if ((*i)->GetID() == BUTTON_WINDOWED)
			{
				i++;
				continue;
			}
		}
		else
		{
			if ((*i)->GetID() == BUTTON_FULLSCREEN)
			{
				i++;
				continue;
			}
		}
		(*i)->Render();
		i++;
	}

	mpD3DSprite->End();

	static char buffer[512];
	
	sprintf_s(buffer, "Sound Volume: %.0f", mSoundVolume*10);

	RECT R1 = {mD3DPP.BackBufferWidth*0.4, mD3DPP.BackBufferHeight*0.43, 0, 0};
	mpD3DMenuFont->DrawTextA(0, buffer, -1, &R1, DT_NOCLIP, D3DCOLOR_ARGB(255, 255, 127, 0));

	sprintf_s(buffer, "Music Volume: %.0f", mMusicVolume*10);
	RECT R2 = {mD3DPP.BackBufferWidth*0.4, mD3DPP.BackBufferHeight*0.53, 0, 0};
	mpD3DMenuFont->DrawTextA(0, buffer, -1, &R2, DT_NOCLIP, D3DCOLOR_ARGB(255, 255, 127, 0));

	if (mLaunchOnRelease)
		sprintf_s(buffer, "Launch on release");
	else
		sprintf_s(buffer, "Launch on click");

	RECT R3 = {mD3DPP.BackBufferWidth*0.4, mD3DPP.BackBufferHeight*0.62, 0, 0};
	mpD3DMenuFont->DrawTextA(0, buffer, -1, &R3, DT_NOCLIP, D3DCOLOR_ARGB(255, 255, 127, 0));

	HR(gD3DDevice->EndScene());
	HR(gD3DDevice->Present( NULL, NULL, NULL, NULL ));
}

////////////////////////////////////////////////
// RenderFPS()
//
// Renders the current FPS count to the screen
////////////////////////////////////////////////
void FuriousTourist::RenderFPS(void)
{
	static char buffer[256];

	sprintf_s(buffer, "FPS = %.2f\n", mFPS);

	RECT R1 = {5, 5, 0, 0};
	mpD3DSmallFont->DrawTextA(0, buffer, -1, &R1, DT_NOCLIP, D3DCOLOR_ARGB(255, 0, 255, 0));
}

////////////////////////////////////////////////
// RenderGame()
//
// The Render function for the game itself (GAMESTATE_PLAY).
// Uses the mGameObjects vector list to render every game
// asset we have.
////////////////////////////////////////////////
void FuriousTourist::RenderGame()
{
	// don't clear the screen contents if we're displaying an overlay screen
	if (mDisplayInGameHelp)
	{
		HR(gD3DDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff404040, 1.0f, 0));
	}
	else if (!mDisplayWinScreen || !mDisplayLoseScreen)
	{
		// use the color of sand as the background color
		HR(gD3DDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffF4E3D7, 1.0f, 0));
	}

	HR(gD3DDevice->BeginScene());

	// if we have help screens to show, render the screen and
	// override all of the commands below by closing the device
	// and returning
	if (mDisplayInGameHelp)
	{
		IDirect3DTexture9* texture = mHelpScreens.operator[](mCurrentHelpScreen);
		mpD3DSprite->Begin(D3DXSPRITE_ALPHABLEND);
		D3DXVECTOR3 pos = D3DXVECTOR3((float)mD3DPP.BackBufferWidth/2, (float)mD3DPP.BackBufferHeight/2, 0.0f);
		D3DXVECTOR3 cen = D3DXVECTOR3((float)HELPSCREEN_W/2, (float)HELPSCREEN_H/2, 0.0f);
		mpD3DSprite->Draw(texture, 0, &cen, &pos, D3DCOLOR_ARGB(255, 255, 255, 255));
		mpD3DSprite->End();
		
		RenderHelpHUD();

		HR(gD3DDevice->EndScene());
		HR(gD3DDevice->Present(0, 0, 0, 0));

		return;
	}

	if (mProjectileState == PROJECTILESTATE_PREPARED)
		RenderRopes();

	RenderBackground();

	// Setup the rendering FX
	mFX->SetValue(mhAmbientLight, &mAmbientLight, sizeof(D3DXCOLOR));
	mFX->SetValue(mhDiffuseLight, &mDiffuseLight, sizeof(D3DXCOLOR));
	mFX->SetValue(mhSpecLight, &mSpecLight, sizeof(D3DXCOLOR));
	mFX->SetValue(mhLightVecW, &mLightVecW, sizeof(D3DXVECTOR3));

	// fill the render info object with necessary info determined this pass
	mRenderInfo.mFX					= mFX;
	mRenderInfo.mhTech				= mhTech;
	mRenderInfo.mhWorld				= mhWorld;	
	mRenderInfo.mhWorldInvTrans		= mhWorldInvTrans;
	mRenderInfo.mhWVP				= mhWVP;
	mRenderInfo.mhAmbientMtrl		= mhAmbientMtrl;
	mRenderInfo.mhAmbientLight		= mhAmbientLight;
	mRenderInfo.mhDiffuseMtrl		= mhDiffuseMtrl;
	mRenderInfo.mhDiffuseLight		= mhDiffuseLight;
	mRenderInfo.mhSpecMtrl			= mhSpecMtrl;
	mRenderInfo.mhSpecLight			= mhSpecLight;
	mRenderInfo.mhSpecPower			= mhSpecPower;
	mRenderInfo.mhLightVecW			= mhLightVecW;
	mRenderInfo.mhEyePos			= mhEyePos;
	mRenderInfo.mhTex				= mhTex;
	mRenderInfo.mView				= mView;
	mRenderInfo.mProj				= mProj;

	// do the relevant number of passes through the Effect file
	UINT numPasses = 0;
	mFX->Begin(&numPasses, 0); // get the number of passes from the effect file
	for(UINT i = 0; i < numPasses; ++i) 
	{
		// begin the pass
		mFX->BeginPass(i);
		
		GameObjects::iterator o = mGameObjects.begin();

		// render game objects (crates, weapons etc.)
		while(o != mGameObjects.end())
		{
			// run the function that manipulates data from the Effect file
			(*o)->Render(mRenderInfo);
			o++;
		}

		// render all markers from both sets (the current set
		// alternates between the two sets depending on
		// the order of shots)
		Markers::iterator x = mMarkerSet1.begin();
		while (x != mMarkerSet1.end())
		{
			((GameObject*)(*x))->Render(mRenderInfo);
			x++;
		}

		x = mMarkerSet2.begin();
		while (x != mMarkerSet2.end())
		{
			((GameObject*)(*x))->Render(mRenderInfo);
			x++;
		}

		// close the pass
		mFX->EndPass();
	}
	// close the entire Effect
	mFX->End();

	if(mShowFPS)
		RenderFPS();

	TEXTMANAGER->Render();

	RenderHUD();
	
	//DebugInfo();

	Particles::iterator p = mParticles.begin();
	while (p != mParticles.end())
	{
		(*p)->Render();
		p++;
	}

	// if we have the end game score screen to show, render the screen and
	// override all of the commands below by closing the device
	// and returning
	if (mDisplayWinScreen || mDisplayLoseScreen)
	{
		RenderEndGameScoreHUD();
	}

	HR(gD3DDevice->EndScene());

	// Present the backbuffer.
	HR(gD3DDevice->Present(0, 0, 0, 0));
}

////////////////////////////////////////////////
// RenderRopes()
//
// Renders the ropes for when the projectile is
// being prepared to be launched.
////////////////////////////////////////////////
void FuriousTourist::RenderRopes()
{
	LPD3DXLINE rope;
	D3DXCreateLine(gD3DDevice, &rope);
	physics::Vector3 start, end1, end2;
	mProjectile->GetBody()->getPosition(&start);
	
	end1 = mCatapultPosition;
	end1.z += CATAPULT1_Z;
	end1.y += CATAPULT_HEIGHT;

	end2 = mCatapultPosition;
	end2.z += CATAPULT2_Z;
	end2.y += CATAPULT_HEIGHT;

	D3DXVECTOR3 lines[] = {	
			D3DXVECTOR3(end1.x, end1.y, end1.z),
			D3DXVECTOR3(start.x, start.y, start.z),
			D3DXVECTOR3(end2.x, end2.y, end2.z)		
		};
	rope->SetWidth(5.0f);
	rope->Begin();
	// use the view*proj matrix to convert the lines from
	// screen coordinates into world coordinates
	rope->DrawTransform(lines, 3, &(mView*mProj), 0xFF000000);
	rope->End();
	rope->Release();
}

////////////////////////////////////////////////
// RenderTitleGraphics()
//
// Renders all of the title graphics to the screen
////////////////////////////////////////////////
void FuriousTourist::RenderTitleGraphics()
{
	D3DXMATRIX S;

	D3DXMatrixScaling(&S, (float)mD3DPP.BackBufferWidth / (float)MENUBACKGROUND_W, (float)mD3DPP.BackBufferHeight / (float)MENUBACKGROUND_H, 1.0f);
	mpD3DSprite->SetTransform(&S);
	mpD3DSprite->Draw(mMenuBackgroundTex, 0, &MENUBG_CENTER, &MENUBG_POSITION, D3DCOLOR_XRGB(255, 255, 255));
	mpD3DSprite->Draw(mMenuTitleTex, 0, &MENUTITLE_CENTER, &mMenuTitlePosition, D3DCOLOR_XRGB(255, 255, 255));
	
	
	D3DXMatrixScaling(&S, (float)mD3DPP.BackBufferWidth * TOURISTTITLE_SCALE / (float)MENUBACKGROUND_W, (float)mD3DPP.BackBufferHeight * TOURISTTITLE_SCALE / (float)MENUBACKGROUND_H, 1.0f);
	D3DXMATRIX T;
	D3DXMatrixTranslation(&T, TOURISTTITLE_POSX, TOURISTTITLE_POSY, 0.0f);
	mpD3DSprite->SetTransform(&(S*T));
	mpD3DSprite->Draw(mTouristTitleTex, 0, &TOURISTTITLE_CENTER, 0, D3DCOLOR_XRGB(255, 255, 255));
}

////////////////////////////////////////////////
// RenderBackground()
//
// Renders the background to the screen. Should be done
// at the start of the render loop, so that other objects
// are drawn on top of it.
////////////////////////////////////////////////
void FuriousTourist::RenderBackground()
{
	mpD3DSprite->Begin(D3DXSPRITE_ALPHABLEND);
	D3DXMATRIX S;
	D3DXMatrixScaling(&S, (float)mD3DPP.BackBufferWidth / (float)BACKDROP_W, (float)mD3DPP.BackBufferHeight / (float)BACKDROP_H * 0.75, 1.0f);
	mpD3DSprite->SetTransform(&S);
	mpD3DSprite->Draw(mBackdrop, 0, &BACKDROP_CENTER, &BACKDROP_POS, D3DCOLOR_ARGB(255, 255, 255, 255));
	mpD3DSprite->End();
}

////////////////////////////////////////////////
// DebugInfo()
//
// Renders some debug info to the screen
////////////////////////////////////////////////
void FuriousTourist::DebugInfo()
{
	static char buffer[256];
	int x = 10;
	int y = 30;
	int num = 0;

	GameObjects::iterator i = mGameObjects.begin();
	while (i != mGameObjects.end())
	{
		sprintf_s(buffer, "Health%i, %i = %i", num, (*i)->GetMaterial(), (*i)->GetHP());
		RECT R = {x, y, 0, 0};
		mpD3DSmallFont->DrawTextA(0, buffer, -1, &R, DT_NOCLIP, D3DCOLOR_ARGB(255, 0, 0, 0));
		y+=10;
		num++;
		i++;
	}
	

	
}

////////////////////////////////////////////////
// LaunchProjectile()
//
// Launches the projectile
////////////////////////////////////////////////
void FuriousTourist::LaunchProjectile(float dt)
{

	// apply the impulse needed to launch the projectile here (also activate gravity)
	//PhysicsEngine::registry.add(mProjectile->GetBody(), mForceDueToGravity);
	mProjectile->GetBody()->setAwake(); // set awake so physics applies to the object
	mProjectile->GetBody()->activate(); // activate so it can collide with other objects

	physics::Vector3 vec, cursorPos, startPos;
	startPos = mProjectileStartPosition;

	cursorPos = physics::Vector3(GetWorldPickingRay());
	vec = startPos - cursorPos;
	if (vec.squareMagnitude() > PROJECTILEPREPARED_DISTANCE * PROJECTILEPREPARED_DISTANCE)
	{
		vec.normalize();
		vec *= PROJECTILEPREPARED_DISTANCE;
	}

	mProjectile->GetBody()->applyForce(vec * PROJECTILE_FORCEFACTOR * (1 / dt) * mProjectile->GetBody()->getMass());
	mProjectile->GetBody()->applyTorque(physics::Vector3(0, 0, -1) * PROJECTILE_TORQUEFACTOR * (1 / dt) * mProjectile->GetBody()->getMass());
	
	mTimeElapsedSinceCreatedLastMarker = 0.0f;
	CreateMarker();

	SOUNDMANAGER->SoundPlay(SOUND_PROJECTILERELEASE);
}

////////////////////////////////////////////////
// LoadAssets()
//
// First run when the game is started. Loads all
// important game assets (textures) and stores them
// in memory for later use. Initializes a lot of
// important values.
////////////////////////////////////////////////
void FuriousTourist::LoadAssets()
{
	D3DXCreateSprite(gD3DDevice, &mpD3DSprite);

	TEXTMANAGER->Initialize(mpD3DSprite);

	mShowFPS = true;

 	AddFontResource("Assets//Textures//Jokerman-Regular.ttf");

	LOGFONT Font ={14,28,0,0,FW_MEDIUM,false,false,false,DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,PROOF_QUALITY,DEFAULT_PITCH,"Jokerman"};
	D3DXCreateFont(gD3DDevice, Font.lfWidth, Font.lfHeight, Font.lfWeight, 1, Font.lfItalic, Font.lfCharSet, Font.lfOutPrecision, Font.lfQuality,Font.lfPitchAndFamily, Font.lfFaceName, &mpD3DMenuFont);

	LOGFONT Font2 = {8,20,0,0,FW_LIGHT,false,false,false,DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,PROOF_QUALITY,DEFAULT_PITCH,"Jokerman"};
	D3DXCreateFont(gD3DDevice, Font2.lfWidth, Font2.lfHeight, Font2.lfWeight, 1, Font2.lfItalic, Font2.lfCharSet, Font2.lfOutPrecision, Font2.lfQuality,Font2.lfPitchAndFamily, Font2.lfFaceName, &mpD3DSmallMenuFont);

	// create a font descriptor
	D3DXFONT_DESC fontDesc;
	
	fontDesc.Height          = 18;
	fontDesc.Width           = 8;
	fontDesc.Weight          = 0;
	fontDesc.MipLevels       = 1;
	fontDesc.Italic          = false;
	fontDesc.CharSet         = DEFAULT_CHARSET;
	fontDesc.OutputPrecision = OUT_DEFAULT_PRECIS;
	fontDesc.Quality         = DEFAULT_QUALITY;
	fontDesc.PitchAndFamily  = DEFAULT_PITCH | FF_DONTCARE;
	_tcscpy(fontDesc.FaceName, _T("Times New Roman"));

	// create the font
	D3DXCreateFontIndirect(gD3DDevice, &fontDesc, &mpD3DSmallFont);

	// create a font
	fontDesc.Height          = 36;
	fontDesc.Width           = 14;
	fontDesc.Weight          = 0;
	fontDesc.MipLevels       = 1;
	fontDesc.Italic          = false;
	fontDesc.CharSet         = DEFAULT_CHARSET;
	fontDesc.OutputPrecision = OUT_DEFAULT_PRECIS;
	fontDesc.Quality         = DEFAULT_QUALITY;
	fontDesc.PitchAndFamily  = DEFAULT_PITCH | FF_DONTCARE;
	_tcscpy(fontDesc.FaceName, _T("Times New Roman"));

	D3DXCreateFontIndirect(gD3DDevice, &fontDesc, &mpD3DLargeFont);

	
	MenuButton* menuButton;

	// Create the main menu buttons
	menuButton		= new MenuButton(BUTTON_PLAY,		BUTTON_MENUPLAY_POS,		BACKBUFFERSIZE, LARGEBUTTON_H, LARGEBUTTON_W,		"Assets//Textures//Menu_LargeEmptyLit.png", "Assets//Textures//Menu_LargeEmptyUnlit.png", "Play", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mMainMenuButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_CREDITS,	BUTTON_MENUCREDITS_POS,		BACKBUFFERSIZE, LARGEBUTTON_H, LARGEBUTTON_W,		"Assets//Textures//Menu_LargeEmptyLit.png", "Assets//Textures//Menu_LargeEmptyUnlit.png", "Credits", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mMainMenuButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_HELP,		BUTTON_MENUHELP_POS,		BACKBUFFERSIZE, LARGEBUTTON_H, LARGEBUTTON_W,		"Assets//Textures//Menu_LargeEmptyLit.png", "Assets//Textures//Menu_LargeEmptyUnlit.png", "Help/\nControls", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mMainMenuButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_OPTIONS,	BUTTON_MENUOPTIONS_POS,		BACKBUFFERSIZE, LARGEBUTTON_H, LARGEBUTTON_W,		"Assets//Textures//Menu_LargeEmptyLit.png", "Assets//Textures//Menu_LargeEmptyUnlit.png", "Options", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mMainMenuButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_QUIT,		BUTTON_MENUQUIT_POS,		BACKBUFFERSIZE, LARGEBUTTON_H, LARGEBUTTON_W,		"Assets//Textures//Menu_LargeEmptyLit.png", "Assets//Textures//Menu_LargeEmptyUnlit.png", "Quit", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mMainMenuButtons.push_back(menuButton);
	
	// Create in-game buttons
	menuButton		= new MenuButton(BUTTON_RESET,		BUTTON_GAMERESET_POS,		BACKBUFFERSIZE, ROUNDBUTTON_H, ROUNDBUTTON_W,		"Assets//Textures//Menu_RoundLit.png", "Assets//Textures//Menu_RoundUnlit.png", "Reset", mpD3DSprite, mpD3DSmallMenuFont, mhMainWnd);
	mGameButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_MENU,		BUTTON_GAMEMENU_POS,		BACKBUFFERSIZE, ROUNDBUTTON_H, ROUNDBUTTON_W,		"Assets//Textures//Menu_RoundLit.png", "Assets//Textures//Menu_RoundUnlit.png", "Menu", mpD3DSprite, mpD3DSmallMenuFont, mhMainWnd);
	mGameButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_TOGGLEHEALTH,	BUTTON_GAMETOGGLEHEALTH_POS,	BACKBUFFERSIZE, ROUNDBUTTON_H, ROUNDBUTTON_W,		"Assets//Textures//Menu_RoundLit.png", "Assets//Textures//Menu_RoundUnlit.png", "Toggle\nHealth", mpD3DSprite, mpD3DSmallMenuFont, mhMainWnd);
	mGameButtons.push_back(menuButton);

	// Create end-game score buttons
	menuButton		= new MenuButton(BUTTON_NEXTLEVEL,	BUTTON_NEXTLEVEL_POS,		BACKBUFFERSIZE, ROUNDBUTTON_H, ROUNDBUTTON_W,		"Assets//Textures//Menu_RoundLit.png", "Assets//Textures//Menu_RoundUnlit.png", "Next\nLevel", mpD3DSprite, mpD3DSmallMenuFont, mhMainWnd);
	mWinLoseScreenButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_RETRYLEVEL,	BUTTON_RETRYLEVEL_POS,		BACKBUFFERSIZE, ROUNDBUTTON_H, ROUNDBUTTON_W,		"Assets//Textures//Menu_RoundLit.png", "Assets//Textures//Menu_RoundUnlit.png", "Retry\nLevel", mpD3DSprite, mpD3DSmallMenuFont, mhMainWnd);
	mWinLoseScreenButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_BACKTOMENU,	BUTTON_BACKTOMENU_POS,		BACKBUFFERSIZE, ROUNDBUTTON_H, ROUNDBUTTON_W,		"Assets//Textures//Menu_RoundLit.png", "Assets//Textures//Menu_RoundUnlit.png", "Menu", mpD3DSprite, mpD3DSmallMenuFont, mhMainWnd);
	mWinLoseScreenButtons.push_back(menuButton);
	
	// ingamehelp buttons
	menuButton		= new MenuButton(BUTTON_NEXTHELP,	BUTTON_GAMENEXTHELP_POS,	BACKBUFFERSIZE, ROUNDBUTTON_H, ROUNDBUTTON_W,		"Assets//Textures//Menu_RoundLit.png", "Assets//Textures//Menu_RoundUnlit.png", "Next", mpD3DSprite, mpD3DSmallMenuFont, mhMainWnd);
	mInGameHelpButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_PREVHELP,	BUTTON_GAMEPREVHELP_POS,	BACKBUFFERSIZE, ROUNDBUTTON_H, ROUNDBUTTON_W,		"Assets//Textures//Menu_RoundLit.png", "Assets//Textures//Menu_RoundUnlit.png", "Prev", mpD3DSprite, mpD3DSmallMenuFont, mhMainWnd);
	mInGameHelpButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_DONEHELP,	BUTTON_GAMENEXTHELP_POS,	BACKBUFFERSIZE, ROUNDBUTTON_H, ROUNDBUTTON_W,		"Assets//Textures//Menu_RoundLit.png", "Assets//Textures//Menu_RoundUnlit.png", "Done", mpD3DSprite, mpD3DSmallMenuFont, mhMainWnd);
	mInGameHelpButtons.push_back(menuButton);

	// Create the options menu buttons
	menuButton		= new MenuButton(BUTTON_WINDOWED,	BUTTON_OPTIONSSWITCHFORMAT_POS,			BACKBUFFERSIZE, LARGEWIDEBUTTON_H, LARGEWIDEBUTTON_W,	"Assets//Textures//Menu_LargeWideEmptyLit.png", "Assets//Textures//Menu_LargeWideEmptyUnlit.png", "Windowed", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mOptionsButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_FULLSCREEN, BUTTON_OPTIONSSWITCHFORMAT_POS,			BACKBUFFERSIZE, LARGEWIDEBUTTON_H, LARGEWIDEBUTTON_W,	"Assets//Textures//Menu_LargeWideEmptyLit.png", "Assets//Textures//Menu_LargeWideEmptyUnlit.png", "Fullscreen", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mOptionsButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_SOUNDUP,	BUTTON_OPTIONSSOUNDUP_POS,				BACKBUFFERSIZE, SMALLWIDEBUTTON_H, SMALLWIDEBUTTON_W,	"Assets//Textures//Menu_SmallWideEmptyLit.png", "Assets//Textures//Menu_SmallWideEmptyUnlit.png", "Up", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mOptionsButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_SOUNDDOWN,	BUTTON_OPTIONSSOUNDDOWN_POS,			BACKBUFFERSIZE, SMALLWIDEBUTTON_H, SMALLWIDEBUTTON_W,	"Assets//Textures//Menu_SmallWideEmptyLit.png", "Assets//Textures//Menu_SmallWideEmptyUnlit.png", "Down", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mOptionsButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_MUSICUP,	BUTTON_OPTIONSMUSICUP_POS,				BACKBUFFERSIZE, SMALLWIDEBUTTON_H, SMALLWIDEBUTTON_W,	"Assets//Textures//Menu_SmallWideEmptyLit.png", "Assets//Textures//Menu_SmallWideEmptyUnlit.png", "Up", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mOptionsButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_MUSICDOWN,	BUTTON_OPTIONSMUSICDOWN_POS,			BACKBUFFERSIZE, SMALLWIDEBUTTON_H, SMALLWIDEBUTTON_W,	"Assets//Textures//Menu_SmallWideEmptyLit.png", "Assets//Textures//Menu_SmallWideEmptyUnlit.png", "Down", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mOptionsButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_BACK,		BUTTON_MENUBACK_POS,					BACKBUFFERSIZE, LARGEBUTTON_H, LARGEBUTTON_W,		"Assets//Textures//Menu_LargeEmptyLit.png", "Assets//Textures//Menu_LargeEmptyUnlit.png", "Back", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mOptionsButtons.push_back(menuButton);
	menuButton		= new MenuButton(BUTTON_CONTROLS,	BUTTON_CONTROLS_POS,					BACKBUFFERSIZE, LARGEBUTTON_H, LARGEBUTTON_W,		"Assets//Textures//Menu_LargeEmptyLit.png", "Assets//Textures//Menu_LargeEmptyUnlit.png", "Control\nMethod", mpD3DSprite, mpD3DSmallMenuFont, mhMainWnd);
	mOptionsButtons.push_back(menuButton);

	// credits buttons
	menuButton		= new MenuButton(BUTTON_BACK,		BUTTON_MENUBACK_POS,					BACKBUFFERSIZE, LARGEBUTTON_H, LARGEBUTTON_W,		"Assets//Textures//Menu_LargeEmptyLit.png", "Assets//Textures//Menu_LargeEmptyUnlit.png", "Back", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mCreditsButtons.push_back(menuButton);

	// help buttons
	menuButton		= new MenuButton(BUTTON_BACK,		BUTTON_MENUBACK_POS,					BACKBUFFERSIZE, LARGEBUTTON_H, LARGEBUTTON_W,		"Assets//Textures//Menu_LargeEmptyLit.png", "Assets//Textures//Menu_LargeEmptyUnlit.png", "Back", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mHelpButtons.push_back(menuButton);

	mLaunchOnRelease = true;

	mWinLoseScreenTex = NULL;

	D3DXCreateTextureFromFileEx(gD3DDevice,
		"Assets//Textures//EndGameScoreScreen.png",
		ENDSCORE_W,
		ENDSCORE_H,
		1,
		0,
		D3DFMT_UNKNOWN,
		D3DPOOL_MANAGED,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		D3DCOLOR_XRGB(255, 255, 255),
		0,
		NULL,
		&mWinLoseScreenTex);

	D3DXCreateTextureFromFileEx(gD3DDevice,
		"Assets//Textures//MenuBackground.png",
		MENUBACKGROUND_W,
		MENUBACKGROUND_H,
		1,
		0,
		D3DFMT_UNKNOWN,
		D3DPOOL_MANAGED,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		D3DCOLOR_XRGB(255, 255, 255),
		0,
		NULL,
		&mMenuBackgroundTex);

	D3DXCreateTextureFromFileEx(gD3DDevice,
		"Assets//Textures//Title.png",
		MENUTITLE_W,
		MENUTITLE_H,
		1,
		0,
		D3DFMT_UNKNOWN,
		D3DPOOL_MANAGED,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		D3DCOLOR_XRGB(255, 255, 255),
		0,
		NULL,
		&mMenuTitleTex);

	D3DXCreateTextureFromFileEx(gD3DDevice,
		"Assets//Textures//FuriousTouristTitle.png",
		TOURISTTITLE_W,
		TOURISTTITLE_H,
		1,
		0,
		D3DFMT_UNKNOWN,
		D3DPOOL_MANAGED,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		D3DCOLOR_XRGB(255, 255, 255),
		0,
		NULL,
		&mTouristTitleTex);

	mMenuTitleRot = 0.0f;
	mMenuTitleLen = 4.0f;

	D3DXCreateTextureFromFileEx(gD3DDevice,
		g_BackdropFiles[BACKDROP_DAY],
		BACKDROP_W,
		BACKDROP_H,
		1,
		0,
		D3DFMT_UNKNOWN,
		D3DPOOL_MANAGED,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		D3DCOLOR_XRGB(255, 255, 255),
		0,
		NULL,
		&mBackdrop);

	D3DXCreateTextureFromFileEx(gD3DDevice,
		"Assets//Textures//WinTouristTex.png",
		WINTOURIST_W,
		WINTOURIST_H,
		1,
		0,
		D3DFMT_UNKNOWN,
		D3DPOOL_MANAGED,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		D3DCOLOR_XRGB(255, 255, 255),
		0,
		NULL,
		&mWinTouristTex);

	D3DXCreateTextureFromFileEx(gD3DDevice,
		"Assets//Textures//LoseTouristTex.png",
		LOSETOURIST_W,
		LOSETOURIST_H,
		1,
		0,
		D3DFMT_UNKNOWN,
		D3DPOOL_MANAGED,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		D3DCOLOR_XRGB(255, 255, 255),
		0,
		NULL,
		&mLoseTouristTex);

	D3DXCreateTextureFromFileEx(gD3DDevice,
		"Assets//Textures//Star.png",
		STAR_W,
		STAR_H,
		1,
		0,
		D3DFMT_UNKNOWN,
		D3DPOOL_MANAGED,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		D3DCOLOR_XRGB(255, 255, 255),
		0,
		NULL,
		&mStarTex);
	
	// initialize the colours of the ambient, diffise and specular lights
	mAmbientLight		= WHITE;
	mDiffuseLight		= WHITE;
	mSpecLight			= WHITE;

	// initialize the light position
	mLightVecW			= D3DXVECTOR3(0.0f, 1.0f, 0.0f);

	// set the attenuation of the specular light (the behaviour of the light as it fades from the central point of impact)
	mAttenuation012		= D3DXVECTOR3(0.5f, 0.0f, 0.0f);

	// create the projection matrix (FOV etc.)
	InitializeProjectionMatrix();

	// initialize the shader FX
	InitializeFX();

	// run this command to get the backbuffer width/height from
	// the size of the window
	OnResetDevice();

	// create the gravity vector
	physics::Vector3 grav = physics::Vector3::DOWN * GRAVITY_STRENGTH;

	// create a gravity force generator
	mForceDueToGravity = new physics::Gravity(grav);

	mExplosiveForce = NULL;

	mSoundVolume = SOUNDVOLUME_START;
	mMusicVolume = MUSICVOLUME_START;

	// load all meshes
	MESHMANAGER->LoadMesh("Assets//Meshes//1 - Seagull.X", BIRDTYPE_SEAGULL);
	MESHMANAGER->LoadMesh("Assets//Meshes//2 - Blackbird.X", BIRDTYPE_BLACKBIRD);
	MESHMANAGER->LoadMesh("Assets//Meshes//3 - Parrot.X", BIRDTYPE_PARROT);
	MESHMANAGER->LoadMesh("Assets//Meshes//4 - Toucan.X", BIRDTYPE_TOUCAN);
	MESHMANAGER->LoadMesh("Assets//Meshes//5 - Coconut_Regular.x", WEAPONTYPE_NORMAL);
	MESHMANAGER->LoadMesh("Assets//Meshes//5 - Coconut_Regular.x", OBJECTTYPE_DEFAULTSPHERE);
	MESHMANAGER->LoadMesh("Assets//Meshes//6 - Coconut_Three.X", WEAPONTYPE_MULTI);
	MESHMANAGER->LoadMesh("Assets//Meshes//7 - Coconut_Rocket.X", WEAPONTYPE_ROCKET);
	MESHMANAGER->LoadMesh("Assets//Meshes//8 - Coconut_Exploding.X", WEAPONTYPE_EXPLODE);
	MESHMANAGER->LoadMesh("Assets//Meshes//PalmTree.X", OBJECTTYPE_CATAPULT);

	float w = 1.0f;
	float h = 1.0f;
	float d = 1.0f;

	// create boxes
	// choose the appropriate texture file
	IDirect3DTexture9* tex;
	IDirect3DVertexBuffer9* vbuffer;
	IDirect3DIndexBuffer9* ibuffer;
	Mtrl *mtrl = new Mtrl(WHITE*0.8f, WHITE, WHITE*0.8f, 8.0f);

	gD3DDevice->CreateVertexBuffer(24 * sizeof(VertexPNT), D3DUSAGE_WRITEONLY,
		0, D3DPOOL_MANAGED,	&vbuffer, 0);

	// Write box vertices to the vertex buffer.
	VertexPNT* v = 0;
	vbuffer->Lock(0, 0, (void**)&v, 0);

	// Fill in the front face vertex data.
	v[0]  = VertexPNT(-w, -h, -d,  0.0f,  0.0f, -1.0f,  1.0f,  0.0f);
	v[1]  = VertexPNT(-w,  h, -d,  0.0f,  0.0f, -1.0f,  0.0f,  0.0f);
	v[2]  = VertexPNT( w,  h, -d,  0.0f,  0.0f, -1.0f,  0.0f,  1.0f);
	v[3]  = VertexPNT( w, -h, -d,  0.0f,  0.0f, -1.0f,  1.0f,  1.0f);

	// Fill in the back face vertex data.
	v[4]  = VertexPNT(-w, -h,  d,  0.0f,  0.0f,  1.0f,  1.0f,  1.0f);
	v[5]  = VertexPNT( w, -h,  d,  0.0f,  0.0f,  1.0f,  0.0f,  1.0f);
	v[6]  = VertexPNT( w,  h,  d,  0.0f,  0.0f,  1.0f,  0.0f,  0.0f);
	v[7]  = VertexPNT(-w,  h,  d,  0.0f,  0.0f,  1.0f,  1.0f,  0.0f);

	// Fill in the top face vertex data.
	v[8]  = VertexPNT(-w,  h, -d,  0.0f,  1.0f,  0.0f,  0.0f,  1.0f);
	v[9]  = VertexPNT(-w,  h,  d,  0.0f,  1.0f,  0.0f,  0.0f,  0.0f);
	v[10] = VertexPNT( w,  h,  d,  0.0f,  1.0f,  0.0f,  1.0f,  0.0f);
	v[11] = VertexPNT( w,  h, -d,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f);

	// Fill in the bottom face vertex data.
	v[12] = VertexPNT(-w, -h, -d,  0.0f, -1.0f,  0.0f,  1.0f,  1.0f);
	v[13] = VertexPNT( w, -h, -d,  0.0f, -1.0f,  0.0f,  0.0f,  1.0f);
	v[14] = VertexPNT( w, -h,  d,  0.0f, -1.0f,  0.0f,  0.0f,  0.0f);
	v[15] = VertexPNT(-w, -h,  d,  0.0f, -1.0f,  0.0f,  1.0f,  0.0f);

	// Fill in the left face vertex data.
	v[16] = VertexPNT(-w, -h,  d, -1.0f,  0.0f,  0.0f,  0.0f,  1.0f);
	v[17] = VertexPNT(-w,  h,  d, -1.0f,  0.0f,  0.0f,  0.0f,  0.0f);
	v[18] = VertexPNT(-w,  h, -d, -1.0f,  0.0f,  0.0f,  1.0f,  0.0f);
	v[19] = VertexPNT(-w, -h, -d, -1.0f,  0.0f,  0.0f,  1.0f,  1.0f);

	// Fill in the right face vertex data.
	v[20] = VertexPNT( w, -h, -d,  1.0f,  0.0f,  0.0f,  0.0f,  1.0f);
	v[21] = VertexPNT( w,  h, -d,  1.0f,  0.0f,  0.0f,  0.0f,  0.0f);
	v[22] = VertexPNT( w,  h,  d,  1.0f,  0.0f,  0.0f,  1.0f,  0.0f);
	v[23] = VertexPNT( w, -h,  d,  1.0f,  0.0f,  0.0f,  1.0f,  1.0f);

	vbuffer->Unlock();


	// Create the vertex buffer.
	gD3DDevice->CreateIndexBuffer(36 * sizeof(WORD),	D3DUSAGE_WRITEONLY,
		D3DFMT_INDEX16,	D3DPOOL_MANAGED, &ibuffer, 0);

	// Write box indices to the index buffer.
	WORD* i = 0;
	ibuffer->Lock(0, 0, (void**)&i, 0);

	// Fill in the front face index data
	i[0] = 0; i[1] = 1; i[2] = 2;
	i[3] = 0; i[4] = 2; i[5] = 3;

	// Fill in the back face index data
	i[6] = 4; i[7]  = 5; i[8]  = 6;
	i[9] = 4; i[10] = 6; i[11] = 7;

	// Fill in the top face index data
	i[12] = 8; i[13] =  9; i[14] = 10;
	i[15] = 8; i[16] = 10; i[17] = 11;

	// Fill in the bottom face index data
	i[18] = 12; i[19] = 13; i[20] = 14;
	i[21] = 12; i[22] = 14; i[23] = 15;

	// Fill in the left face index data
	i[24] = 16; i[25] = 17; i[26] = 18;
	i[27] = 16; i[28] = 18; i[29] = 19;

	// Fill in the right face index data
	i[30] = 20; i[31] = 21; i[32] = 22;
	i[33] = 20; i[34] = 22; i[35] = 23;

	ibuffer->Unlock();

	// add this vbuffer/ibuffer combo to the mesh manager using a different
	// texture each time
	D3DXCreateTextureFromFile(gD3DDevice, "Assets//Textures//marble.bmp", &tex);
	MESHMANAGER->AddBuffer(vbuffer, ibuffer, mtrl, tex, OBJECTTYPE_STONEBOX);

	D3DXCreateTextureFromFile(gD3DDevice, "Assets//Textures//crate.jpg", &tex);
	MESHMANAGER->AddBuffer(vbuffer, ibuffer, mtrl, tex, OBJECTTYPE_WOODBOX);

	D3DXCreateTextureFromFile(gD3DDevice, "Assets//Textures//ExplodeCrate.png", &tex);
	MESHMANAGER->AddBuffer(vbuffer, ibuffer, mtrl, tex, OBJECTTYPE_EXPLOSIVEBOX);

	D3DXCreateTextureFromFile(gD3DDevice, "Assets//Textures//Sand.png", &tex);
	MESHMANAGER->AddBuffer(vbuffer, ibuffer, mtrl, tex, OBJECTTYPE_SANDBOX);

	D3DXCreateTextureFromFile(gD3DDevice, "Assets//Textures//crate.jpg", &tex);
	MESHMANAGER->AddBuffer(vbuffer, ibuffer, mtrl, tex, OBJECTTYPE_DEFAULTBOX);

	// create a sphere for different materials
	ID3DXMesh* sphere;
	HR(D3DXCreateSphere(gD3DDevice, 1.0f, 30, 30, &sphere, 0));

	D3DVERTEXELEMENT9 elements[64];
	UINT numElements = 0;
	VertexPNT::Decl->GetDeclaration(elements, &numElements);

	ID3DXMesh* temp = 0;
	HR(sphere->CloneMesh(D3DXMESH_SYSTEMMEM, elements, gD3DDevice, &temp));

	ReleaseCOM(sphere);

	// Now generate texture coordinates for each vertex.
	VertexPNT* vertices = 0;
	HR(temp->LockVertexBuffer(0, (void**)&vertices));

	for(UINT i = 0; i < temp->GetNumVertices(); ++i)
	{
		// Convert to spherical coordinates.
		D3DXVECTOR3 p = vertices[i].pos;


		float theta = atan2f(p.z, p.x);
		float phi   = acosf(p.y / sqrtf(p.x*p.x+p.y*p.y+p.z*p.z));

		// Phi and theta give the texture coordinates, but are not in 
		// the range [0, 1], so scale them into that range.

		float u = theta / (2.0f*D3DX_PI);
		float v = phi   / D3DX_PI;

		// Save texture coordinates.

		vertices[i].tex0.x = u;
		vertices[i].tex0.y = v;
	}
	HR(temp->UnlockVertexBuffer());

	// Clone back to a hardware mesh.
	HR(temp->CloneMesh(D3DXMESH_MANAGED | D3DXMESH_WRITEONLY,
		elements, gD3DDevice, &sphere));

	ReleaseCOM(temp);

	D3DXCreateTextureFromFile(gD3DDevice, "Assets//Textures//marble.bmp", &tex);
	MESHMANAGER->LoadMesh(sphere, *mtrl, tex, OBJECTTYPE_STONESPHERE);

	// load sound files
	SOUNDMANAGER->LoadSound("Assets//Sound//BlackbirdDeath.wav",		SOUND_BLACKBIRDDEATH,		VOLUME_BLACKBIRDDEATH);
	SOUNDMANAGER->LoadSound("Assets//Sound//SeagullDeath.wav",			SOUND_SEAGULLDEATH,			VOLUME_SEAGULLDEATH);
	SOUNDMANAGER->LoadSound("Assets//Sound//ParrotDeath.wav",			SOUND_PARROTDEATH,			VOLUME_PARROTDEATH);
	SOUNDMANAGER->LoadSound("Assets//Sound//ToucanDeath.wav",			SOUND_TOUCANDEATH,			VOLUME_TOUCANDEATH);
	SOUNDMANAGER->LoadSound("Assets//Sound//BirdSquawk.wav",			SOUND_BIRDSQUAWK,			VOLUME_BIRDSQUAWK);
	SOUNDMANAGER->LoadSound("Assets//Sound//WoodBreak.mp3",				SOUND_WOODBREAK,			VOLUME_WOODBREAK);
	SOUNDMANAGER->LoadSound("Assets//Sound//WoodImpact.mp3",			SOUND_WOODIMPACT,			VOLUME_WOODIMPACT);
	SOUNDMANAGER->LoadSound("Assets//Sound//StoneBreak.wav",			SOUND_STONEBREAK,			VOLUME_STONEBREAK);
	SOUNDMANAGER->LoadSound("Assets//Sound//StoneImpact.mp3",			SOUND_STONEIMPACT,			VOLUME_STONEIMPACT);
	SOUNDMANAGER->LoadSound("Assets//Sound//Explosion.wav",				SOUND_EXPLOSION,			VOLUME_EXPLOSION);
	SOUNDMANAGER->LoadSound("Assets//Sound//Pop.wav",					SOUND_POP,					VOLUME_POP);
	SOUNDMANAGER->LoadSound("Assets//Sound//ProjectilePrepare.wav",		SOUND_PROJECTILEPREPARE,	VOLUME_PROJECTILEPREPARE);
	SOUNDMANAGER->LoadSound("Assets//Sound//ProjectileRelease.wav",		SOUND_PROJECTILERELEASE,	VOLUME_PROJECTILERELEASE);
	SOUNDMANAGER->LoadSound("Assets//Sound//ProjectileLoad.mp3",		SOUND_PROJECTILELOAD,		VOLUME_PROJECTILELOAD);
	SOUNDMANAGER->LoadSound("Assets//Sound//RocketnutLaunch.mp3",		SOUND_ROCKETNUTLAUNCH,		VOLUME_ROCKETNUTLAUNCH);
	SOUNDMANAGER->LoadSound("Assets//Sound//MultinutSplit.wav",			SOUND_MULTINUTSPLIT,		VOLUME_MULTINUTSPLIT);
	SOUNDMANAGER->LoadSound("Assets//Sound//MenuClick1.wav",			SOUND_MENUCLICK1,			VOLUME_MENUCLICK1);
	SOUNDMANAGER->LoadSound("Assets//Sound//MenuClick2.wav",			SOUND_MENUCLICK2,			VOLUME_MENUCLICK2);
	SOUNDMANAGER->LoadSound("Assets//Sound//MenuError.wav",				SOUND_MENUERROR,			VOLUME_MENUERROR);
	SOUNDMANAGER->LoadSound("Assets//Sound//CoconutImpact.wav",			SOUND_COCONUTIMPACT,		VOLUME_COCONUTIMPACT);
	SOUNDMANAGER->LoadSound("Assets//Sound//BeachAmbience.mp3",			SOUND_BEACHAMBIENCE,		VOLUME_BEACHAMBIENCE);
	SOUNDMANAGER->LoadSound("Assets//Sound//AmbientRandom1.mp3",		SOUND_AMBIENTRANDOM1,		VOLUME_AMBIENTRANDOM1);
	SOUNDMANAGER->LoadSound("Assets//Sound//AmbientRandom2.mp3",		SOUND_AMBIENTRANDOM2,		VOLUME_AMBIENTRANDOM2);
	SOUNDMANAGER->LoadSound("Assets//Sound//AmbientRandom3.wav",		SOUND_AMBIENTRANDOM3,		VOLUME_AMBIENTRANDOM3);
	SOUNDMANAGER->LoadSound("Assets//Sound//AmbientRandom4.mp3",		SOUND_AMBIENTRANDOM4,		VOLUME_AMBIENTRANDOM4);
	SOUNDMANAGER->LoadSound("Assets//Sound//AmbientRandom5.mp3",		SOUND_AMBIENTRANDOM5,		VOLUME_AMBIENTRANDOM5);
	SOUNDMANAGER->LoadSound("Assets//Sound//AmbientRandom6.wav",		SOUND_AMBIENTRANDOM6,		VOLUME_AMBIENTRANDOM6);
	SOUNDMANAGER->LoadSound("Assets//Sound//AmbientRandom7.wav",		SOUND_AMBIENTRANDOM7,		VOLUME_AMBIENTRANDOM7);
	SOUNDMANAGER->LoadSound("Assets//Sound//AmbientRandom8.mp3",		SOUND_AMBIENTRANDOM8,		VOLUME_AMBIENTRANDOM8);
	SOUNDMANAGER->LoadSound("Assets//Sound//AmbientRandom9.mp3",		SOUND_AMBIENTRANDOM9,		VOLUME_AMBIENTRANDOM9);
	SOUNDMANAGER->LoadMusic("Assets//Sound//RoadToParadise30s.mp3",		MUSIC_TITLE,				VOLUME_TITLEMUSIC);
	SOUNDMANAGER->LoadSound("Assets//Sound//Win.mp3",					SOUND_WIN,					VOLUME_WIN);
	SOUNDMANAGER->LoadSound("Assets//Sound//Lose.mp3",					SOUND_LOSE,					VOLUME_LOSE);
	SOUNDMANAGER->LoadSound("Assets//Sound//SilverBronzeDing.mp3",		SOUND_BRONZEDING,			VOLUME_DING);
	SOUNDMANAGER->LoadSound("Assets//Sound//SilverBronzeDing.mp3",		SOUND_SILVERDING,			VOLUME_DING);
	SOUNDMANAGER->LoadSound("Assets//Sound//GoldDing.mp3",		SOUND_GOLDDING,				VOLUME_DING);
	SOUNDMANAGER->SetVolume(mSoundVolume, mMusicVolume);

	// set the initial game state
	mState = GAMESTATE_INTRO;
}

////////////////////////////////////////////////
// CreateGameAssets()
//
// Creates the ground plane and all assets to be 
// used in the current game level.
// Assigns the first weapon to mProjectile and
// ensures it starts in the correct position
////////////////////////////////////////////////
void FuriousTourist::CreateGameAssets()
{
	
	mNumBirdsLeft = 0;
	// load the current level
	LoadMap(g_LevelArray[mCurrentLevel-1]);

	// load the first weapon
	GameObjects::iterator w = mWeapons.begin();
	mProjectile = (*w);

	mProjectileState = PROJECTILESTATE_READY;
	mProjectile->GetBody()->setPosition(mProjectileStartPosition);
	mProjectile->GetBody()->stop();
}

////////////////////////////////////////////////
// DestroyGameAssets()
//
// Destroys all game assets. Should be run at the
// end of a level, or end of a game.
////////////////////////////////////////////////
void FuriousTourist::DestroyGameAssets()
{
	int size = mGameObjects.size();
	GameObjects::iterator i = mGameObjects.begin();
	while (i != mGameObjects.end())
	{
		//delete *i;
		i = mGameObjects.erase(i);
	}

	PhysicsEngine::RemoveAllObjects();
	PhysicsEngine::RemoveAllParticleEffects();

	Particles::iterator p = mParticles.begin();
	while(p != mParticles.end())
	{
		p = mParticles.erase(p);
	}

	// clear out the weapon list
	size = mWeapons.size();
	i = mWeapons.begin();
	while (i != mWeapons.end())
	{
		i = mWeapons.erase(i);
	}

	// clear all help screens
	while(mHelpScreens.size() > 0)
	{
		HelpScreens::iterator h = mHelpScreens.begin();
		(*h)->Release();
		mHelpScreens.erase(h);
	};
}

////////////////////////////////////////////////
// CreateAsset()
//
// Creates a single asset for the game
////////////////////////////////////////////////
void FuriousTourist::CreateAsset(physics::CollisionPrimitive *primitive, GameObject *object)
{
	mGameObjects.push_back(object);
	PhysicsEngine::AddObject(primitive);
	//PhysicsEngine::registry.add(primitive->body, mForceDueToGravity);
	
}

////////////////////////////////////////////////
// DestroyAsset()
//
// Destroys one asset from the game
////////////////////////////////////////////////
void FuriousTourist::DestroyAsset(physics::RigidBody *body)
{
	GameObjects::iterator x = mGameObjects.begin();
	while (x != mGameObjects.end())
	{
		if(body == (*x)->GetBody()) // keep a pointer to the body for a moment
		{
			mGameObjects.erase(x); // remove the object from the game
			PhysicsEngine::RemoveObject(body); // remove the object from the physics engine
			break;
		}
		x++;
	}
}

////////////////////////////////////////////////
// PlayIntroMovie()
//
// Plays and introductory movie when the game is launched.
// Handles keyboard input so it can be skipped.
////////////////////////////////////////////////
void FuriousTourist::PlayIntroMovie()
{
	//////////////////////////////////////////
	// DirectShow movie
	//////////////////////////////////////////

	//// initialize the COM object library
	//CoInitialize(NULL);
	//// create a filter graph manager to help us manage filters and the data stream
	//CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&mpGraphBuilder);
	//// create an IMediaControl object to control streaming
	//mpGraphBuilder->QueryInterface(IID_IMediaControl, (void**)&mpMediaControl);
	//// create an IMediaEvent object that receives events from teh Filter Graph Manager
	//mpGraphBuilder->QueryInterface(IID_IMediaEvent, (void**)&mpMediaEvent);
	//// build a filter graph for our file and prepare it to stream
	//mpGraphBuilder->RenderFile(L"Assets/Intro.wmv", NULL);
	////video window
	//mpMediaControl->QueryInterface(IID_IVideoWindow, (void**)&mpVideoWindow);

	//// setup the window

	//mpVideoWindow->put_Owner((OAHWND)mhMainWnd);

	//// set the style
	//mpVideoWindow->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE);

	//// obtain the size of the window
	//RECT WinRect;
	//GetClientRect(mhMainWnd, &WinRect);
	//// set the video size to the size of the window
	//mpVideoWindow->SetWindowPosition(WinRect.left, WinRect.top, WinRect.right, WinRect.bottom);

	//// run the video
	//mpMediaControl->Run();

	//// wait for the video to finish
	//// not a good idea to use INFINITE in a real program...
	//long evCode;
	////mpMediaEvent->WaitForCompletion(INFINITE, &evCode);
	//LONG_PTR eventParam1, eventParam2;

	//// interrupt the movie when RETURN or ESCAPE are pressed
	//// otherwise hte movie will keep playing until complete
	//while(true)
	//{
	//	gameInput->poll();

	//	mpMediaEvent->GetEvent(&evCode, &eventParam1, &eventParam2, 0);

	//	if (gameInput->keyDown(DIK_RETURN) || gameInput->keyDown(DIK_ESCAPE) || gameInput->keyDown(DIK_SPACE))
	//	{
	//		mpMediaControl->Stop();
	//		break;
	//	}

	//	if (evCode == EC_COMPLETE)
	//		break;
	//}

	//// End Full Screen
	//if (!mD3DPP.Windowed)
	//	mpVideoWindow->put_FullScreenMode(OAFALSE);

	//// go to the menu state
	//mState = GAMESTATE_MENU;
}

////////////////////////////////////////////////
// IncreaseVolume()
//
// Increments the current volume by 1 (scale of 1-10)
////////////////////////////////////////////////
void FuriousTourist::IncreaseVolume(float &v)
{
	v += 0.1f;
	if (v > 1.0f)
	{
		v = 1.0f;
		SOUNDMANAGER->SoundPlay(SOUND_MENUERROR);
	}
	else
	{
		SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
	}
}

////////////////////////////////////////////////
// DecreaseVolume()
//
// Creates the ground plane and all assets to be 
// used in the current game level.
// Assigns the first weapon to mProjectile and
// ensures it starts in the correct position
////////////////////////////////////////////////
void FuriousTourist::DecreaseVolume(float &v)
{
	v -= 0.1f;
	// because its unsigned, we have to check if its 'greater than ten' instead of 'less than zero'
	// i.e. unsigned 0 minus 1 = 65535
	if (v < 0.0f)
	{
		v = 0.0f;
		SOUNDMANAGER->SoundPlay(SOUND_MENUERROR);
	}
	else
	{
		SOUNDMANAGER->SoundPlay(SOUND_MENUCLICK1);
	}
}

////////////////////////////////////////////////
// MoveTitleGraphic()
//
// Spins the title graphic around to give it more
// life. Each call will increase the current rotation
// a little more, based on the current time. The
// angular velocity should thus remain constant.
////////////////////////////////////////////////
void FuriousTourist::MoveTitleGraphic(float dt)
{
	mMenuTitleRot += 1.0f * dt;
	//if (mMenuTitleRot > 2 * D3DX_PI)
		//mMenuTitleRot = 0.0f;

	mMenuTitlePosition = D3DXVECTOR3(WINDOWED_DEFAULTWIDTH * 0.3f, WINDOWED_DEFAULTHEIGHT * 0.1f, 0.0f);
	mMenuTitlePosition += mMenuTitleLen * D3DXVECTOR3(4*sinf(0.5*mMenuTitleRot), cosf(0.3*mMenuTitleRot), 0.0f);
}

////////////////////////////////////////////////
// InitializeFX()
//
// Initializes the D3DX Shader
////////////////////////////////////////////////
void FuriousTourist::InitializeFX()
{
	ID3DXBuffer* errors = 0;
	// load in the Effect file and check for errors
	D3DXCreateEffectFromFile(gD3DDevice, "Effects/dirLightTex.fx", 0, 0, D3DXSHADER_DEBUG, 0, &mFX, &errors);
	if (errors)
		MessageBox(0, (char*)errors->GetBufferPointer(), 0, 0);

	// Obtain handles from the Effect file
	mhTech           = mFX->GetTechniqueByName("DirLightTexTech");
	mhWVP            = mFX->GetParameterByName(0, "gWVP");
	mhWorldInvTrans  = mFX->GetParameterByName(0, "gWorldInvTrans");
	mhEyePos         = mFX->GetParameterByName(0, "gEyePosW");
	mhWorld          = mFX->GetParameterByName(0, "gWorld");
	mhAmbientLight   = mFX->GetParameterByName(0, "gAmbientLight");
	mhDiffuseLight   = mFX->GetParameterByName(0, "gDiffuseLight");
	mhSpecLight      = mFX->GetParameterByName(0, "gSpecularLight");
	mhLightVecW      = mFX->GetParameterByName(0, "gLightVecW");
	mhAmbientMtrl    = mFX->GetParameterByName(0, "gAmbientMtrl");
	mhDiffuseMtrl    = mFX->GetParameterByName(0, "gDiffuseMtrl");
	mhSpecMtrl       = mFX->GetParameterByName(0, "gSpecularMtrl");
	mhSpecPower      = mFX->GetParameterByName(0, "gSpecularPower");
	mhTex            = mFX->GetParameterByName(0, "gTex");

}

////////////////////////////////////////////////
// RenderHUD()
//
// Renders important HUD elements. For use during
// actual gameplay (not menus).
////////////////////////////////////////////////
void FuriousTourist::RenderHUD()
{
	mpD3DSprite->Begin(D3DXSPRITE_ALPHABLEND);

	D3DXMATRIX S;
	// reset the scaling matrix to render the buttons
	D3DXMatrixScaling(&S, 1.0f, 1.0f, 1.0f);
	mpD3DSprite->SetTransform(&S);

	int w = mD3DPP.BackBufferWidth;
	int h = mD3DPP.BackBufferHeight;

	static char buffer[256];
	
	sprintf_s(buffer, "Score: %i\n", mScore);
	RECT R = {w*0.1, h*0.1, w*0.1, h*0.1};
	mpD3DMenuFont->DrawTextA(mpD3DSprite, buffer, -1, &R, DT_NOCLIP | DT_LEFT, D3DCOLOR_ARGB(255, 0, 0, 0));
	
	                               
	sprintf_s(buffer, "Level: %i", mCurrentLevel);
	RECT R2 = {w*0.1, h*0.05, w*0.1, h*0.05};
	mpD3DMenuFont->DrawTextA(mpD3DSprite, buffer, -1, &R2, DT_NOCLIP | DT_LEFT, D3DCOLOR_ARGB(255, 0, 0, 0));
	
	Buttons::iterator i = mGameButtons.begin();
	while (i != mGameButtons.end())
	{
		(*i)->Render();
		i++;
	}

	mpD3DSprite->End();

}

////////////////////////////////////////////////
// RenderHelpHUD()
//
// Renders help HUD elements. For use during
// help menus
////////////////////////////////////////////////
void FuriousTourist::RenderHelpHUD()
{
	mpD3DSprite->Begin(D3DXSPRITE_ALPHABLEND);

	D3DXMATRIX S;
	// reset the scaling matrix to render the buttons
	D3DXMatrixScaling(&S, 1.0f, 1.0f, 1.0f);
	mpD3DSprite->SetTransform(&S);

	Buttons::iterator i = mInGameHelpButtons.begin();
	while (i != mInGameHelpButtons.end())
	{
		int id = (*i)->GetID();
		int size = mHelpScreens.size()-1;
		// only render during particular situations
		switch(id)
		{
		case BUTTON_PREVHELP:
			if (mCurrentHelpScreen != 0)
				(*i)->Render();
			break;
		case BUTTON_DONEHELP:
			if (mCurrentHelpScreen == size)
				(*i)->Render();
			break;
		case BUTTON_NEXTHELP:
			if (mCurrentHelpScreen < size)
				(*i)->Render();
			break;
		}

		i++;
	}

	mpD3DSprite->End();

}

////////////////////////////////////////////////
// RenderEndGameScoreHUD()
//
// Renders end game HUD elements. For use after
// the current level has ended
////////////////////////////////////////////////
void FuriousTourist::RenderEndGameScoreHUD()
{
	mpD3DSprite->Begin(D3DXSPRITE_ALPHABLEND);

	// render the end-game background texture here
	D3DXMATRIX S, T;
	int w = mD3DPP.BackBufferWidth;
	int h = mD3DPP.BackBufferHeight;

	D3DXMatrixScaling(&S, ENDSCORE_SCALE * w, ENDSCORE_SCALE * w, 1.0f);
	D3DXMatrixTranslation(&T, ENDSCORE_POSX, ENDSCORE_POSY, 0.0f);
	mpD3DSprite->SetTransform(&(S*T));
	D3DXVECTOR3 cen = D3DXVECTOR3((float)ENDSCORE_W/2, (float)ENDSCORE_H/2, 0.0f);
	mpD3DSprite->Draw(mWinLoseScreenTex, 0, &cen, 0, D3DCOLOR_ARGB(255, 255, 255, 255));

	static char buffer[256];
	
	// reset the scaling matrix to render the buttons
	D3DXMatrixScaling(&S, 1.0f, 1.0f, 1.0f);
	mpD3DSprite->SetTransform(&S);

	if (mDisplayWinScreen)
	{
		D3DXMatrixScaling(&S, WINLOSETOURIST_SCALE * w, WINLOSETOURIST_SCALE * w, 1.0f);
		D3DXMatrixTranslation(&T, WINLOSETOURIST_POSX, WINLOSETOURIST_POSY, 0.0f);
		mpD3DSprite->SetTransform(&(S*T));
		D3DXVECTOR3 cen = D3DXVECTOR3((float)WINTOURIST_W/2, (float)WINTOURIST_H/2, 0.0f);
		mpD3DSprite->Draw(mWinTouristTex, 0, &cen, 0, D3DCOLOR_ARGB(255, 255, 255, 255));

		D3DXMatrixScaling(&S, 1.0f, 1.0f, 1.0f);
		mpD3DSprite->SetTransform(&S);

		RECT R1 = {w*0.5, h*0.65, w*0.5, h*0.65};
		sprintf_s(buffer, "Score: %i", mScore);
		mpD3DMenuFont->DrawTextA(mpD3DSprite, buffer, -1, &R1, DT_NOCLIP | DT_CENTER, D3DCOLOR_XRGB(255, 147, 0));

		RECT R2 = {w*0.5, h*0.7, w*0.5, h*0.7};
		int highScore = GetHighScore();
		if (mScore > highScore)
		{
			RECT R = {w*0.6, h*0.6, w*0.6, h*0.6};
			sprintf_s(buffer, "New Highscore!");
			mpD3DSmallMenuFont->DrawTextA(mpD3DSprite, buffer, -1, &R, DT_NOCLIP | DT_CENTER, D3DCOLOR_XRGB(255, 147, 0));
			highScore = mScore;
		}
		sprintf_s(buffer, "Highscore: %i", highScore);
		mpD3DMenuFont->DrawTextA(mpD3DSprite, buffer, -1, &R2, DT_NOCLIP | DT_CENTER, D3DCOLOR_XRGB(255, 147, 0));

		D3DXMatrixScaling(&S, STAR_SCALE * w, STAR_SCALE * w, 1.0f);
		D3DXMatrixTranslation(&T, STAR1_POSX, STAR1_POSY, 0.0f);
		mpD3DSprite->SetTransform(&(S*T));
		cen = D3DXVECTOR3((float)STAR_W/2, (float)STAR_H/2, 0.0f);
		mpD3DSprite->Draw(mStarTex, 0, &cen, 0, D3DCOLOR_ARGB(255, 255, 255, 255));

		if (!mPlayedBronzeDing)
			{
				mPlayedBronzeDing = true;
				SOUNDMANAGER->SoundPlay(SOUND_BRONZEDING);
			}


		if (mTimeElapsedSinceShowScore > SCORE_SHOWSILVER)
		{
			if (mScore >= g_LevelScoreLimits[mCurrentLevel-1][SCORE_SILVER])
			{
				if (!mPlayedSilverDing)
				{
					mPlayedSilverDing = true;
					SOUNDMANAGER->SoundPlay(SOUND_SILVERDING);
				}

				D3DXMatrixScaling(&S, STAR_SCALE * w, STAR_SCALE * w, 1.0f);
				D3DXMatrixTranslation(&T, STAR2_POSX, STAR2_POSY, 0.0f);
				mpD3DSprite->SetTransform(&(S*T));
				D3DXVECTOR3 cen = D3DXVECTOR3((float)STAR_W/2, (float)STAR_H/2, 0.0f);
				mpD3DSprite->Draw(mStarTex, 0, &cen, 0, D3DCOLOR_ARGB(255, 255, 255, 255));
			}
		}

		if (mTimeElapsedSinceShowScore > SCORE_SHOWGOLD)
		{

			if (mScore >= g_LevelScoreLimits[mCurrentLevel-1][SCORE_GOLD])
			{

				if (!mPlayedGoldDing)
				{
					mPlayedGoldDing = true;
					SOUNDMANAGER->SoundPlay(SOUND_GOLDDING);
				}

				D3DXMatrixScaling(&S, STAR_SCALE * w, STAR_SCALE * w, 1.0f);
				D3DXMatrixTranslation(&T, STAR3_POSX, STAR3_POSY, 0.0f);
				mpD3DSprite->SetTransform(&(S*T));
				D3DXVECTOR3 cen = D3DXVECTOR3((float)STAR_W/2, (float)STAR_H/2, 0.0f);
				mpD3DSprite->Draw(mStarTex, 0, &cen, 0, D3DCOLOR_ARGB(255, 255, 255, 255));
			}
		}
	}

	if (mDisplayLoseScreen)
	{
		D3DXMatrixScaling(&S, WINLOSETOURIST_SCALE * w, WINLOSETOURIST_SCALE * w, 1.0f);
		D3DXMatrixTranslation(&T, WINLOSETOURIST_POSX, WINLOSETOURIST_POSY, 0.0f);
		mpD3DSprite->SetTransform(&(S*T));
		D3DXVECTOR3 cen = D3DXVECTOR3((float)LOSETOURIST_W/2, (float)LOSETOURIST_H/2, 0.0f);
		mpD3DSprite->Draw(mLoseTouristTex, 0, &cen, 0, D3DCOLOR_ARGB(255, 255, 255, 255));

		D3DXMatrixScaling(&S, 1.0f, 1.0f, 1.0f);
		mpD3DSprite->SetTransform(&S);

		RECT R1 = {w*0.5, h*0.7, w*0.5, h*0.7};
		sprintf_s(buffer, "You lost! :(");
		mpD3DMenuFont->DrawTextA(mpD3DSprite, buffer, -1, &R1, DT_NOCLIP | DT_CENTER, D3DCOLOR_XRGB(255, 147, 0));
	}

	D3DXMatrixScaling(&S, 1.0f, 1.0f, 1.0f);
	mpD3DSprite->SetTransform(&S);
	
	Buttons::iterator i = mWinLoseScreenButtons.begin();
	while (i != mWinLoseScreenButtons.end())
	{
		int id = (*i)->GetID();

		if (mDisplayLoseScreen && id == BUTTON_NEXTLEVEL)
		{
			// do nothing
		}
		else
		{
			(*i)->Render();
		}

		i++;
	}

	mpD3DSprite->End();

}


////////////////////////////////////////////////
// InitGame()
//
// (Re)Initializes the current level by destroying
// everything we currently have, creating everything
// we want and setting some global values.
////////////////////////////////////////////////
void FuriousTourist::InitGame()
{
	// (re)initialize the game by destroying everything, 
	// recreating everything and setting some global
	// values back to the needed value.
	DestroyGameAssets();
	ClearAllMarkers();
	CreateGameAssets();

	// initialize important game variables
	mWaitCount = false;
	mEndGameCount = false;
	mButtonDown = false;
	mButtonReady = false;
	mButtonReleased = false;
	mSpecialUsed = false;
	mPlaySquawk = true;
	mCameraMoving = false;
	mpCurrentMarkers = &mMarkerSet1;
	mProjectileState = PROJECTILESTATE_READY;
	PhysicsEngine::globalRegistry.add(mForceDueToGravity);
	mCameraPosX = 0.0f;
	mCameraPosY = 30.0f;
	mCameraPosZ = 0.0f;
	mCameraRadius = -150.0f;
	mCameraRotationY = 0.0f;
	mScore = 0;
	mAmbientTriggerTime = 0.0f;
	SOUNDMANAGER->SoundStop();
	mDisplayWinScreen = false;
	mDisplayLoseScreen = false;
	mBeginWinScreenDelay = false;
	mTimeElapsedSinceWin = 0.0f;
	mTimeElapsedSinceShowScore = 0.0f;
	mSpareWeapons = mWeapons.size();
	mPlayedBronzeDing = false;
	mPlayedSilverDing = false;
	mPlayedGoldDing = false;

	// if we're still showing health from the last level, show it for this level
	if (mShowHealth)
	{
		GameObjects::iterator g = mGameObjects.begin();
		while (g != mGameObjects.end())
		{
			(*g)->ToggleShowHealth();
			g++;
		}
	}

	if (mHelpScreens.size() > 0)
	{
		mDisplayInGameHelp = true;
		mCurrentHelpScreen = 0;
	}
	else
	{
		mDisplayInGameHelp = false;
		SOUNDMANAGER->SoundPlay(SOUND_BEACHAMBIENCE);
	}

	// make all game objects generate their transformation matrices BEFORE
	// any collision detection happens
	PhysicsEngine::endFrame();
}

////////////////////////////////////////////////
// UpdateViewMatrix()
//
// Should be called every iteration. Updates the view
// matrix based on the current position of the camera.
////////////////////////////////////////////////
void FuriousTourist::UpdateViewMatrix(float dt)
{
	// no moving camera, currently. This code will be more important once
	// we implement a moving camera.
	if (mProjectileState == PROJECTILESTATE_WAITING || mProjectileState == PROJECTILESTATE_INFLIGHT)
	{
		if (gameInput->keyDown(DIK_A))
			mCameraRotationY += dt;
		if (gameInput->keyDown(DIK_D))
			mCameraRotationY -= dt;
	}
	else if (mProjectileState == PROJECTILESTATE_READY)
	{
		if (mCameraRotationY != 0.0f)
		{
			mCameraMoving = true;
			if (mCameraRotationY > 0.25f)
			{
				mCameraRotationY -= 1.5f*dt;
			}
			else if (mCameraRotationY < -0.25f)
			{
				mCameraRotationY += 1.5f*dt;
			}
			else
			{
				mCameraRotationY = 0.0f;
				mCameraMoving = false;
			}
		}
	}
	else
	{
		mCameraRotationY = 0.0f;
	}

	// if pressing the RMB
	if (gameInput->mouseButtonDown(1))
	{
		mCameraPosX += gameInput->mouseDX() * CAMERA_MOVESPEED;
		mCameraPosY -= gameInput->mouseDY() * CAMERA_MOVESPEED;

		if (mCameraPosX < mBarrierLeft)
			mCameraPosX = mBarrierLeft;

		if (mCameraPosY > mBarrierRoof)
			mCameraPosY = mBarrierRoof;

		if (mCameraPosX > mBarrierRight)
			mCameraPosX = mBarrierRight;

		if (mCameraPosY < mBarrierGround)
			mCameraPosY = mBarrierGround;
	}

	mCameraRadius += gameInput->mouseDZ() * CAMERA_ZOOMSPEED;
	
	// camera Z is negative, so flip the signs
	if (-mCameraRadius < CAMERA_RADIUSMIN)
		mCameraRadius = -CAMERA_RADIUSMIN;

	if (-mCameraRadius > CAMERA_RADIUSMAX)
		mCameraRadius = -CAMERA_RADIUSMAX;

	float x = mCameraRadius * sinf(mCameraRotationY);
	float z = mCameraRadius * cosf(mCameraRotationY);

	//D3DXVECTOR3 pos(0, 30, -150);
	D3DXVECTOR3 pos(mCameraPosX + x, mCameraPosY, mCameraPosZ + z);
	D3DXVECTOR3 target(mCameraPosX, mCameraPosY, mCameraPosZ);
	D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
	D3DXMatrixLookAtLH(&mView, &pos, &target, &up);

	// this is important so that the Effect file knows where the camera position is
	// relative to other points. This is so it can render a specular lighting effect
	// that makes sense to the camera's whereabouts. Comment this out for weird fun.
	mFX->SetValue(mhEyePos, &pos, sizeof(D3DXVECTOR3));
}

////////////////////////////////////////////////
// InitializeProjectionMatrix()
//
// Initializes the projection matrix, based on the
// current backbuffer size
////////////////////////////////////////////////
void FuriousTourist::InitializeProjectionMatrix()
{
	float w = (float)mD3DPP.BackBufferWidth;
	float h = (float)mD3DPP.BackBufferHeight;
	D3DXMatrixPerspectiveFovLH(&mProj, D3DX_PI * 0.25f, w/h, 1.0f, 5000.0f);
}

////////////////////////////////////////////////
// GetWorldPickingRay()
//
// Generates a picking ray based on the current
// camera and mouse cursor position. Since this
// game works in two dimensions we automatically
// extrapolate the ray into a position vector on
// the XY plane and return it.
////////////////////////////////////////////////
D3DXVECTOR3 FuriousTourist::GetWorldPickingRay()
{
	// this function takes the position and orientation of the camera and determines
	// the appropriate origin and direction of the ray we will need to figure out
	// which object has been selected

	// Get the clicked screen point.
	POINT s;
	GetCursorPos(&s);           

	// Make it relative to the client area window.
	ScreenToClient(mhMainWnd, &s);

	// By the way we've been constructing things, the entire
	// back buffer is the viewport.
	float w = (float)mD3DPP.BackBufferWidth;
	float h = (float)mD3DPP.BackBufferHeight;

	D3DXMATRIX proj = mProj;

	float x = (2.0f*s.x/w - 1.0f) / proj(0,0);
	float y = (-2.0f*s.y/h + 1.0f) / proj(1,1);

	// Build picking ray in view space.
	D3DXVECTOR3 origin(0.0f, 0.0f, 0.0f);
	D3DXVECTOR3 dir(x, y, 1.0f);

	// So if the view matrix transforms coordinates from
	// world space to view space, then the inverse of the
	// view matrix transforms coordinates from view space
	// to world space.
	D3DXVECTOR3 originW, dirW;
	D3DXMATRIX invView;
	D3DXMatrixInverse(&invView, 0, &mView);

	// Transform picking ray to world space.
	D3DXVec3TransformCoord(&originW, &origin, &invView);
	D3DXVec3TransformNormal(&dirW, &dir, &invView);
	D3DXVec3Normalize(&dirW, &dirW);

	// this is enough to generate the ray based on the camera and cursor
	// positions, but for this game we want a vector only on the XY plane (z = 0)

	// figure out how many times we need to add the direction
	// vector to the origin to get Z to be zero
	float dist = originW.z / dirW.z;

	// Some simple vector math and we have the xy coordinates when
	// z is zero
	D3DXVECTOR3 position = originW - dist * dirW;

	return position;
}

D3DXVECTOR3 FuriousTourist::GetScreenPosition(D3DXVECTOR3 position)
{
	D3DXMATRIX m;
	D3DXVECTOR4 s;
	D3DXVECTOR3 w;

	w = position;

	//VIEW * PROJECTION
	m = mView * mProj;

	//get vectors from view * proj
	s.x = w.x * m._11 + w.y * m._21 + w.z * m._31 + m._41;
	s.y = w.x * m._12 + w.y * m._22 + w.z * m._32 + m._42;
	s.z = w.x * m._13 + w.y * m._23 + w.z * m._33 + m._43;
	s.w = w.x * m._14 + w.y * m._24 + w.z * m._34 + m._44;

	//get inverse of w
	float w_inv = 1.0f / s.w;
	//get center of screen
	float fWidth2 = mD3DPP.BackBufferWidth * 0.5f;
	float fHeight2 = mD3DPP.BackBufferHeight * 0.5f;

	//get screen coordinates
	D3DXVECTOR3 ScreenPosition;
	ScreenPosition.x = (1.0f + (s.x * w_inv)) * fWidth2;
	ScreenPosition.y = (fHeight2*2.0f) - ((1.0f + (s.y * w_inv)) * fHeight2);
	ScreenPosition.z = 0.0f;
	
	return ScreenPosition;
}

////////////////////////////////////////////////
// LoadMap()
//
// Loads information from the map file passed in.
////////////////////////////////////////////////
void FuriousTourist::LoadMap(char* name)
{
	// create a file stream
	ifstream fin;
	fin.open(name); // open the file

	assert(fin.good()); // throw an assertion if the file could not be read

	// some strings we'll need. No point recreating them over and over
	std::string box   ("BOX");
	std::string sphere ("SPHERE");

	std::string wood  ("WOOD");
	std::string stone ("STONE");
	std::string explosive ("EXPLOSIVE");

	std::string leftwall ("LEFTWALL");
	std::string rightwall ("RIGHTWALL");
	std::string roof ("ROOF");
	std::string ground ("GROUND");
	std::string catapult ("CATAPULT");
	std::string world ("WORLD");

	std::string bird  ("BIRD");
	std::string blackbird ("BLACKBIRD");
	std::string seagull ("SEAGULL");
	std::string parrot ("PARROT");
	std::string toucan ("TOUCAN");

	std::string weapons_start ("WPN_START");
	std::string coconut ("WPN_NORMAL");
	std::string multinut("WPN_MULTI");
	std::string rocketnut("WPN_ROCKET");
	std::string explodenut("WPN_EXPLODE");
	std::string weapons_end("WPN_END");

	std::string help1("HELP_1");
	std::string help2("HELP_2");
	std::string help3("HELP_3");
	std::string help4("HELP_4");

	std::string backdropDay("BACKDROP_DAY");
	std::string backdropSunset("BACKDROP_SUNSET");

	while (!fin.eof())
	{
		// read the entire line into memory
		char buf[MAX_CHARS_PER_LINE];
		fin.getline(buf, MAX_CHARS_PER_LINE);

		// parse the line using the delimiter
		int n = 0;

		char* token[MAX_TOKENS_PER_LINE] = {0}; // init to zero

		// parse
		token[0] = strtok(buf, DELIMITER); // first token
		if (token[0]) // false if line is blank
		{
			for (n = 1; n < MAX_TOKENS_PER_LINE; n++)
			{
				token[n] = strtok(0, DELIMITER); // subsequent tokens
				if (!token[n])
					break; // no more tokens
			}
		}

		// now process the data and move on to the next line
		// 'n' is the number of tokens we've picked up at 
		// this point

		GameObject* pGameObject;
		physics::CollisionPlane* pPlane = NULL;
		physics::CollisionPrimitive* pPrimitive = NULL;
		Sphere* pSphere = NULL;
		Box* pBox = NULL;

		ObjectMaterial material;
		ObjectType type = OBJECTTYPE_DEFAULTSPHERE;
		
		bool worldBox = false;

		// create some pointers we'll need
		if (leftwall.compare(token[0]) == 0)
		{
			// create the left wall plane
			float x;
			ConvertToFloat(token[1], x);
			pPlane = new physics::CollisionPlane;
			pPlane->direction = physics::Vector3(1, 0, 0);
			pPlane->distance = x;
			pPrimitive = pPlane;
			PhysicsEngine::AddObject(pPrimitive);

			mBarrierLeft = x;
		} 
		else if (rightwall.compare(token[0]) == 0)
		{
			// create the right wall plane
			float x;
			ConvertToFloat(token[1], x);
			pPlane = new physics::CollisionPlane;
			pPlane->direction = physics::Vector3(-1, 0, 0);
			pPlane->distance = -x;
			pPrimitive = pPlane;
			PhysicsEngine::AddObject(pPrimitive);

			mBarrierRight = x;
		}
		else if (roof.compare(token[0]) == 0)
		{
			// create the roof plane
			float y;
			ConvertToFloat(token[1], y);
			pPlane = new physics::CollisionPlane;
			pPlane->direction = physics::Vector3(0, -1, 0);
			pPlane->distance = -y;
			pPrimitive = pPlane;
			PhysicsEngine::AddObject(pPrimitive);

			mBarrierRoof = y;
		}
		else if (ground.compare(token[0]) == 0)
		{
			float y;
			ConvertToFloat(token[1], y);
			// Create the ground plane
			pPlane = new physics::CollisionPlane;
			pPlane->direction = physics::Vector3(0, 1, 0);
			pPlane->distance = 0;
			pPrimitive = pPlane;
			PhysicsEngine::AddObject(pPrimitive);

			mBarrierGround = y;
		}
		else if (catapult.compare(token[0]) == 0)
		{
			// create the palm trees
			float x, y;
			ConvertToFloat(token[1], x);
			ConvertToFloat(token[2], y);
			pSphere = new Sphere(0.1f, OBJECTMATERIAL_CATAPULT, OBJECTTYPE_CATAPULT);
			pSphere->body->setPosition(physics::Vector3(x, y, CATAPULT1_Z));
			pSphere->body->setOrientation(1, 0, 0, 0);
			pSphere->body->deactivate();
			pPrimitive = pSphere;
			PhysicsEngine::AddObject(pPrimitive);
			pGameObject = pSphere;
			mGameObjects.push_back(pGameObject);

			pSphere = new Sphere(0.1f, OBJECTMATERIAL_CATAPULT, OBJECTTYPE_CATAPULT);
			pSphere->body->setPosition(physics::Vector3(x, y, CATAPULT2_Z));
			pSphere->body->setOrientation(1, 0, 0, 0);
			pSphere->body->deactivate();
			pPrimitive = pSphere;
			PhysicsEngine::AddObject(pPrimitive);
			pGameObject = pSphere;
			mGameObjects.push_back(pGameObject);

			mCatapultPosition = physics::Vector3(x, y, 0);
			mProjectileStartPosition = mCatapultPosition;
			mProjectileStartPosition.y += CATAPULT_HEIGHT;
		}	
		else if (backdropDay.compare(token[0]) == 0)
		{
			// get rid of the current backdrop
			if (mBackdrop != NULL)
				mBackdrop->Release();
			D3DXCreateTextureFromFileEx(gD3DDevice, g_BackdropFiles[BACKDROP_DAY], BACKDROP_W, BACKDROP_H, 1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255), 0, NULL, &mBackdrop);
		}
		else if (backdropSunset.compare(token[0]) == 0)
		{
			// get rid of the current backdrop
			if (mBackdrop != NULL)
				mBackdrop->Release();
			D3DXCreateTextureFromFileEx(gD3DDevice, g_BackdropFiles[BACKDROP_SUNSET], BACKDROP_W, BACKDROP_H, 1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255), 0, NULL, &mBackdrop);
		}
		// check if the level has help screen information attached
		else if (help1.compare(token[0]) == 0)
		{
			
			for (int i = HELP1START; i <= HELP1END; i++)
			{
				IDirect3DTexture9 *image;
				D3DXCreateTextureFromFileEx(gD3DDevice, g_HelpScreenFiles[i], HELPSCREEN_W, HELPSCREEN_H, 1, 0, D3DFMT_UNKNOWN,	D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255),	0,	NULL, &image);
				mHelpScreens.push_back(image);
			} 
		}
		else if (help2.compare(token[0]) == 0)
		{
			for (int i = HELP2START; i <= HELP2END; i++)
			{
				IDirect3DTexture9 *image;
				D3DXCreateTextureFromFileEx(gD3DDevice, g_HelpScreenFiles[i], HELPSCREEN_W, HELPSCREEN_H, 1, 0, D3DFMT_UNKNOWN,	D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255),	0,	NULL, &image);
				mHelpScreens.push_back(image);
			} 
		}
		else if (help3.compare(token[0]) == 0)
		{
			for (int i = HELP3START; i <= HELP3END; i++)
			{
				IDirect3DTexture9 *image;
				D3DXCreateTextureFromFileEx(gD3DDevice, g_HelpScreenFiles[i], HELPSCREEN_W, HELPSCREEN_H, 1, 0, D3DFMT_UNKNOWN,	D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255),	0,	NULL, &image);
				mHelpScreens.push_back(image);
			} 
		}
		else if (help4.compare(token[0]) == 0)
		{
			for (int i = HELP4START; i <= HELP4END; i++)
			{
				IDirect3DTexture9 *image;
				D3DXCreateTextureFromFileEx(gD3DDevice, g_HelpScreenFiles[i], HELPSCREEN_W, HELPSCREEN_H, 1, 0, D3DFMT_UNKNOWN,	D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255),	0,	NULL, &image);
				mHelpScreens.push_back(image);
			}
		}

		// make sure token[1] actually exists first
		if (n > 1)
		{
			if (wood.compare(token[1]) == 0)
			{
				material = OBJECTMATERIAL_WOOD;
			}
			else if (stone.compare(token[1]) == 0)
			{
				material = OBJECTMATERIAL_STONE;
			}
			else if (explosive.compare(token[1]) == 0)
			{
				material = OBJECTMATERIAL_EXPLOSIVE;
			}
			else if (world.compare(token[1]) == 0)
			{
				material = OBJECTMATERIAL_SAND;
				worldBox = true;
			}
			else if (bird.compare(token[1]) == 0)
			{
				material = OBJECTMATERIAL_BIRD;
				// if the object is a bird, we need to increment the counter of Birds
				if (blackbird.compare(token[2]) == 0)
				{
					type = BIRDTYPE_BLACKBIRD;
				}
				else if (seagull.compare(token[2]) == 0)
				{
					type = BIRDTYPE_SEAGULL;
				}
				else if (parrot.compare(token[2]) == 0)
				{
					type = BIRDTYPE_PARROT;
				}
				else if (toucan.compare(token[2]) == 0)
				{
					type = BIRDTYPE_TOUCAN;
				} 
				else
				{
					type = OBJECTTYPE_DEFAULTSPHERE;
				}
				mNumBirdsLeft++;
			}
			else
			{
				material = OBJECTMATERIAL_DEFAULT;
			}

			// do string compares as a workaround. Don't really know
			// how to compare using char*s.
			if (box.compare(token[0]) == 0)
			{
				// create a box
				float x, y, z, w, h, d;

				ConvertToFloat(token[3], x);
				ConvertToFloat(token[4], y);
				ConvertToFloat(token[5], z);
				ConvertToFloat(token[6], w);
				ConvertToFloat(token[7], h);
				ConvertToFloat(token[8], d);

				pBox = new Box(w, h, d, material);		// create the box
				pBox->body->setPosition(physics::Vector3((physics::real)x, (physics::real)y, 0)); // set its position
				pBox->body->setOrientation(1, 0, 0, z);

				// special case for world boxes
				if (worldBox)
				{
					// world boxes have infinite mass i.e. they cannot be moved
					// by collisions
					pBox->body->setInverseMass(0);
					pBox->mHasHealth = false;
				}

				pPrimitive = pBox;	// set the Primitive pointer to the box
				PhysicsEngine::AddObject(pPrimitive);	// add the primitive to the physics engine
				//PhysicsEngine::registry.add(pPrimitive->body, mForceDueToGravity);	// add the primitive's body to the list of objects that get affected by gravity
				pGameObject = pBox; // set the game object pointer to the box
				mGameObjects.push_back(pGameObject); // add it to the list of objects
			}
			else if (sphere.compare(token[0]) == 0)
			{
				// create a sphere
				float x, y, z, r;

				if (material == OBJECTMATERIAL_STONE)
					type = OBJECTTYPE_STONESPHERE;

				ConvertToFloat(token[3], x);
				ConvertToFloat(token[4], y);
				ConvertToFloat(token[5], z);
				ConvertToFloat(token[6], r);

				pSphere = new Sphere(r, material, type);
				pSphere->body->setPosition(physics::Vector3((physics::real)x, (physics::real)y, 0));
				pSphere->body->setOrientation(1, 0, 0, z);
				pPrimitive = pSphere;
				PhysicsEngine::AddObject(pPrimitive);
				pGameObject = pSphere;
				mGameObjects.push_back(pGameObject);
				//PhysicsEngine::registry.add(pPrimitive->body, mForceDueToGravity);
			}
			else if (weapons_start.compare(token[0]) == 0)
			{
				// list of weapons
				int numWeapons = 0;
				int i = 1;
				material = OBJECTMATERIAL_COCONUT;
				while(true)
				{
					if (weapons_end.compare(token[i]) == 0)
						break;
					else if (coconut.compare(token[i]) == 0)
						pSphere = new Sphere(COCONUT_RADIUS, material, WEAPONTYPE_NORMAL);
				
					else if (multinut.compare(token[i]) == 0)
						pSphere = new Sphere(MULTINUT_RADIUS, material, WEAPONTYPE_MULTI);
				
					else if (rocketnut.compare(token[i]) == 0)
						pSphere = new Sphere(ROCKETNUT_RADIUS, material, WEAPONTYPE_ROCKET);
				
					else if (explodenut.compare(token[i]) == 0)
						pSphere = new Sphere(EXPLODENUT_RADIUS, material, WEAPONTYPE_EXPLODE);

					physics::Vector3 pos = mCatapultPosition;
					pos.y += 3;
					physics::Vector3 sep = PROJECTILEUNLOADED_SEPARATEDISTANCE;
					pos.addScaledVector(sep, i);

					pSphere->body->setPosition(pos);
					pSphere->body->setOrientation(1, 0, 0, 0);
					pSphere->body->deactivate();
					pPrimitive = pSphere;
					PhysicsEngine::AddObject(pPrimitive);
					pGameObject = pSphere;
					mGameObjects.push_back(pGameObject);
					mWeapons.push_back(pSphere);
					// don't add gravity to the object like other spheres

					i++;
				}
			}
		}
	}
}

////////////////////////////////////////////////
// GetUnlockedLevel()
//
// Gets the number of the most unlocked level
////////////////////////////////////////////////
int FuriousTourist::GetUnlockedLevel()
{
	char *name = "Levels//Unlocked.dat";

	// create a file stream
	ifstream fin;
	fin.open(name); // open the file

	assert(fin.good()); // throw an assertion if the file could not be read

	/*while (!fin.eof())
	{
		char buf[2];
		fin.getline(buf, 2);
	}*/

	char buf[8];
	fin.getline(buf, 8);

	int level;
	ConvertToInt(buf, level);

	fin.close();

	return level;
}

////////////////////////////////////////////////
// ReplaceUnlockedLevel()
//
// Replaces the unlocked level in the 
// appropriate file
////////////////////////////////////////////////
void FuriousTourist::ReplaceUnlockedLevel(int level)
{
	char *name = "Levels//Unlocked.dat";

	// create a file stream
	ifstream fin;
	fin.open(name); // open the file

	assert(fin.good()); // throw an assertion if the file could not be read

	char buf[8];
	fin.getline(buf, 8);

	int unlocked;
	ConvertToInt(buf, unlocked);

	if (unlocked >= level)
		return;

	fin.close();

	std::ofstream fout;
	fout.open(name);

	assert(fout.good());

	fout << level;

	fout.clear();

	fout.close();
}

////////////////////////////////////////////////
// GetHighScore()
//
// Gets the highscore value of the current level
////////////////////////////////////////////////
int FuriousTourist::GetHighScore()
{
	/*
	char *name = "Levels//HighScore.dat";

	// create a file stream
	ifstream fin;
	fin.open(name); // open the file

	assert(fin.good()); // throw an assertion if the file could not be read

	char buf[2];

	for (int i = 0; i < mCurrentLevel; i++)
		fin.getline(buf, 2);

	int highScore;
	ConvertToInt(buf, highScore);

	return highScore;
	*/

	/*

	char *name = "Levels//HighScore.dat";

	std::vector<std::string> file;
	std::string line;
	file.clear();
	std::ifstream infile (name, std::ios_base::in);
	while (getline(infile, line, '\n'))
	{
		file.push_back (line);
	}

	infile.close();

	int highScore;
	ConvertToInt((char*) &file[mCurrentLevel-1], highScore);

	return highScore;
	*/

	/*std::vector<int> elements;
	elements.push_back(0);

	std::ifstream infile; 
	infile.open("Levels//HighScore.dat", std::ios::in | std::ios::binary); 
	infile.seekg (0, std::ios::end); 
	elements.resize(infile.tellg()/sizeof(int)); 
	infile.seekg (0, std::ios::beg); 
	if (elements.size() > 0)
		infile.read( (char *) &elements[0], elements.capacity()*sizeof(int)); 
	infile.close(); 

	int highScore = 0;
	if (elements.size() < mCurrentLevel)
		return highScore;
	else 
		return elements[mCurrentLevel-1];*/

	int highScore = 0;

    ifstream infile("Levels//HighScore.dat", std::ios::in | std::ios::binary);

    assert(infile.good());

	int num = 1;
	while(!infile.eof())
	{
		// if it failed to read the value in, we must not have a high score value for that level
		if (!infile.read((char*)&highScore, sizeof(int)))
		{
			highScore = 0;
			break;
		}
		else
		{
			if (num == mCurrentLevel)
				break;
			else
				num++;
		}
	}    

	infile.close();
	
	return highScore;

}

////////////////////////////////////////////////
// SaveHighScore()
//
// Saves the highscore value
////////////////////////////////////////////////
void FuriousTourist::SaveHighScore()
{
	std::vector<int> elements;

	std::ifstream infile; 
	infile.open("Levels//HighScore.dat", std::ios::in | std::ios::binary); 
	infile.seekg (0, std::ios::end); 
	elements.resize(infile.tellg()/sizeof(int)); 
	infile.seekg (0, std::ios::beg); 
	if (elements.size() > 0)
		infile.read( (char *) &elements[0], elements.capacity()*sizeof(int)); 
	infile.close(); 

	int highScore = mScore;
	if (elements.size() < mCurrentLevel)
	{
		int num = mCurrentLevel - elements.size();
		for (int i = 0; i < num; i++)
		{
			if (i == mCurrentLevel)
				elements.push_back(mScore);
			else
				elements.push_back(0);
		}
	}
	
	elements[mCurrentLevel-1] = mScore;

	std::ofstream outfile("Levels//HighScore.dat", std::ios::binary);

	for (int i = 0; i < elements.size(); i++)
	{
		outfile.write((char*) &elements[i], sizeof(elements[i]));
	}

	outfile.close();

	/*
	char *name = "Levels//HighScore.dat";

	std::vector<std::string> file;
	std::string line;
	file.clear();
	std::ifstream infile (name, std::ios_base::in);
	while (getline(infile, line, '\n'))
	{
		file.push_back (line);
	}

	infile.close();

	std::ofstream fout;

	// ofstream out("test", ios::out | ios::binary); // write in binary!
	fout.open(name);

	assert(fout.good());

	fout.clear();

	// if there isn't a vector representing this level, we need to create it
	if (file.size() < mCurrentLevel)
	{
		int num = mCurrentLevel - file.size();
		for (int i = 0; i < num; i++)
		{
			file.push_back("0");
		}
	}

	file[mCurrentLevel-1] = mScore;

	for (int i = 0; i < file.size(); i++)
	{
		fout.write((char*) &file[i], sizeof(file[i]));
	}

	fout.close();
	*/
}

////////////////////////////////////////////////
// ConvertToFloat()
//
// A helper function to turn a char* which
// is known to represent a float, into a usable
// float value.
////////////////////////////////////////////////
bool ConvertToFloat( char *c , float &f )
{ 
	bool neg = false ;

	if ( *c == '-' ) 
		neg = true ;

	if ( neg ) 
		++c ;

	if ( *c == '\0' ) 
		return false ;

	f = 0 ;

	while ( *c != '\0' && *c != '.' )
	{ 
		if ( *c < '0' || *c > '9' ) 
			return false ;

		f = f * 10 + *c++ - '0' ;
	}


	if ( *c == '.' )
	{ 
		double weight = 1 ;
		while ( *++c != '\0' )
		{ 
			if ( *c < '0' || *c > '9' ) 
				false ;

			f += ( *c - '0' ) / ( weight *= 10 ) ;
		}
	}

	if ( neg ) f = - f ;

	return true ;
}

////////////////////////////////////////////////
// ConvertToInt()
//
// A helper function to turn a char* which
// is known to represent an int, into a usable
// int value
////////////////////////////////////////////////
bool ConvertToInt( char *c , int &i )
{ 
	i = 0 ;
	
	if ( *c == '\0' ) 
		return false ;

	while ( *c != '\0' && *c != '.' )
	{ 
		if ( *c < '0' || *c > '9' ) 
			return false ;

		i = i * 10 + *c++ - '0' ;
	}

	return true ;
}

////////////////////////////////////////////////
// SetProjectile()
//
// Sets the projectile pointer to the given object.
////////////////////////////////////////////////
void FuriousTourist::SetProjectile(GameObject *object)
{
	mProjectile = object;
}

////////////////////////////////////////////////
// ClearFirstWeapon()
//
// Sets the first weapon pointer to NULL. Useful
// when a coconut explodes, to make the GameObject*
// unreferencable.
////////////////////////////////////////////////
void FuriousTourist::ClearFirstWeapon(void)
{
	mWeapons[0] = NULL;
}

////////////////////////////////////////////////
// LoadNextWeapon()
//
// Loads the next weapon into the catapult by
// removing the old weapon and setting the mProjectile
// pointer to the next one. Returns false if there are
// no weapons left.
////////////////////////////////////////////////
bool FuriousTourist::LoadNextWeapon()
{
	// remove the weapon from the list of game objects to prevent rendering
	GameObjects::iterator i = mGameObjects.begin();
	GameObjects::iterator w = mWeapons.begin();
	
	// uncomment this to prevent projectiles being destroyed each round
	// note: code doesn't remove the two extra coconuts created by
	// multinut specials
	/*while(i != mGameObjects.end())
	{
		// find the object and remove it from the list of game objects
 		if ((*i)->GetBody() == (*w)->GetBody())
		{
			mGameObjects.erase(i);
			break;
		}
		else
		{
			i++;
		}
	}*/

	
	// remove the object from the PhysicsEngine to prevent physics processing
	//PhysicsEngine::RemoveObject((*w)->GetBody());
	
	// remove the object from the list of weapons
	w = mWeapons.erase(w);
	
	if (mWeapons.size() == 0)
		return false;
	else
	{
		// set the projectile to the next weapon
		mProjectile = (*w);
	}
		

	return true;

}

////////////////////////////////////////////////
// GenerateExplosion()
//
// Generates an explosion at the given location
////////////////////////////////////////////////
void FuriousTourist::GenerateExplosion(physics::Vector3 detonation)
{
	// create an explosion sprite
	D3DXVECTOR3 pos;
	pos.x = detonation.x;
	pos.y = detonation.y;
	pos.z = detonation.z;

	SpriteData data;
	data.filename = "Assets//Textures//Explosion.png";
	data.frameHeight = 128;
	data.frameWidth = 128;
	data.numCols = 8;
	data.numRows = 1;

	ParticleEffect* explosionEffect = new ParticleEffect(mpD3DSprite);
	explosionEffect->AddParticles(1, data, 0.5, 0.5, 0, 0, 0, 1, 0.3f, detonation, true);

	mParticles.push_back(explosionEffect);

	mExplosiveForce = new physics::Explosion(detonation, EXPLODE_MAXRADIUS, EXPLODE_STRENGTH);
	PhysicsEngine::globalRegistry.add((physics::ForceGenerator*)mExplosiveForce);
	PhysicsEngine::AddParticleEffect(explosionEffect);

	SOUNDMANAGER->SoundPlay(SOUND_EXPLOSION);

	// this bool signals the game to tell the physics engine to remove
	// this force after the next iteration
	mStopExplosion = true;

	TEXTMANAGER->AddFloatingText(mpD3DMenuFont, "BOOM!", EXPLOSIONTEXT_LIFETIME, GetScreenPosition(pos), EXPLOSIONTEXT_MINSCALE, EXPLOSIONTEXT_MAXSCALE, EXPLOSIONTEXT_COLOR);
}

////////////////////////////////////////////////
// CreateMarker()
//
// Creates a marker at the location of the current
// Projectile
////////////////////////////////////////////////
void FuriousTourist::CreateMarker(void)
{
	// don't want to run functions on mProjectile if there is
	// no data there.
	if (mProjectile == NULL)
		return;

	// get the position of the projectile
	physics::Vector3 pos;
	mProjectile->GetBody()->getPosition(&pos);

	// create a new sphere in this location, using default
	// info (looks like a baby coconut),
	// and add it to the list of markers for rendering
	Sphere* pMarker = new Sphere(MARKER_RADIUS);
	pMarker->body->setPosition(pos);
	pMarker->body->calculateDerivedData();
	mpCurrentMarkers->push_back(pMarker);
}

////////////////////////////////////////////////
// ClearPreviousMarkers()
//
// Removes all markers from the non-current list
////////////////////////////////////////////////
void FuriousTourist::ClearPreviousMarkers(void)
{
	// figure out which is the set of markers
	// from the LAST shot
	Markers *prevMarkers;

	if (mpCurrentMarkers == &mMarkerSet1)
		prevMarkers = &mMarkerSet2;
	else if (mpCurrentMarkers == &mMarkerSet2)
		prevMarkers = &mMarkerSet1;

	// clear out all of the markers
	Markers::iterator x = prevMarkers->begin();
	while (prevMarkers->size() > 0)
	{
		delete *x;
		x = prevMarkers->erase(x);
	}

	// make the current set of markers the now-empty set
	if (mpCurrentMarkers == &mMarkerSet1)
		mpCurrentMarkers = &mMarkerSet2;
	else if (mpCurrentMarkers == &mMarkerSet2)
		mpCurrentMarkers = &mMarkerSet1;

}

////////////////////////////////////////////////
// ClearAllMarkers()
//
// Removes all markers from ALL lists
////////////////////////////////////////////////
void FuriousTourist::ClearAllMarkers(void)
{
	// clear out all of the markers
	Markers::iterator x = mMarkerSet1.begin();
	while (mMarkerSet1.size() > 0)
	{
		delete *x;
		x = mMarkerSet1.erase(x);
	}

	x = mMarkerSet2.begin();
	while (mMarkerSet2.size() > 0)
	{
		delete *x;
		x = mMarkerSet2.erase(x);
	}

	// make the current set of markers the first empty set
	mpCurrentMarkers = &mMarkerSet1;
}


////////////////////////////////////////////////
// CreateLevelSelectButtons()
//
// Creates the buttons for the level select menu
////////////////////////////////////////////////
void FuriousTourist::CreateLevelSelectButtons(void)
{
	mUnlockedLevel = GetUnlockedLevel();

	MenuButton* menuButton;

	menuButton		= new MenuButton(BUTTON_BACK,		BUTTON_MENUBACK_POS,					BACKBUFFERSIZE, LARGEBUTTON_H, LARGEBUTTON_W,		"Assets//Textures//Menu_LargeEmptyLit.png", "Assets//Textures//Menu_LargeEmptyUnlit.png", "Back", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
	mLevelSelectButtons.push_back(menuButton);

	int row = 0;
	int col = 0;

	for (UINT levelNum = 0; levelNum < BUTTON_LEVELEND-BUTTON_LEVELSTART-1; levelNum++)
	{
		// col and rol are used in the definition of BUTTON_LEVELSELECT_POS
		if (col % 5 == 0)
		{
			col = 0;
			row ++;
		}
		static char buffer[4];
		sprintf_s(buffer, "%i", levelNum+1);

		if (levelNum < mUnlockedLevel)
		{
			menuButton = new MenuButton(levelNum+BUTTON_LEVELSTART+1, BUTTON_LEVELSELECT_POS,		BACKBUFFERSIZE, LEVELBUTTON_H, LEVELBUTTON_W,		"Assets//Textures//Menu_UnlockLit.png",	"Assets//Textures//Menu_UnlockUnlit.png",	buffer, mpD3DSprite, mpD3DMenuFont, mhMainWnd);
		}
		else
		{
			menuButton = new MenuButton(levelNum+BUTTON_LEVELSTART+1, BUTTON_LEVELSELECT_POS,		BACKBUFFERSIZE, LEVELBUTTON_H, LEVELBUTTON_W,		"Assets//Textures//Menu_LockLit.png",	"Assets//Textures//Menu_LockUnlit.png", "", mpD3DSprite, mpD3DMenuFont, mhMainWnd);
		}
		mLevelSelectButtons.push_back(menuButton);
		col++;
	}
}

////////////////////////////////////////////////
// DeleteMenuButtons()
//
// Deletes the buttons for the level select menu
////////////////////////////////////////////////
void FuriousTourist::DeleteButtons(Buttons &buttonList)
{
	Buttons::iterator i;
	while (buttonList.size() > 0)
	{
		i = buttonList.begin();
		delete *i;
		buttonList.erase(i);
	}
}